diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe648eaf7c..6ee9473d07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ concurrency: on: pull_request: - # Runs on all PRs +# Runs on all PRs push: branches: - develop @@ -208,7 +208,8 @@ jobs: restore-keys: ${{ runner.os }}-gradle - name: Run steady-state integration tests env: - RADIXDLT_LOG_LEVEL: warn + # Might be set to warn for debugging purposes. Warning, log file will be huge. + RADIXDLT_LOG_LEVEL: error run: ./gradlew clean runSteadyStateIntegrationTests --info --refresh-dependencies targeted-integration: name: Targeted integration tests @@ -228,7 +229,8 @@ jobs: restore-keys: ${{ runner.os }}-gradle - name: Run targeted integration tests env: - RADIXDLT_LOG_LEVEL: warn + # Might be set to warn for debugging purposes. Warning, log file will be huge. + RADIXDLT_LOG_LEVEL: error run: ./gradlew clean runTargetedIntegrationTests --info --refresh-dependencies --parallel cross-xwin: name: Cross compile to Windows diff --git a/Dockerfile b/Dockerfile index be0db21497..4ec5e57be9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,13 +50,13 @@ ENV VERSION_LAST_TAG=$VERSION_LAST_TAG RUN apt-get update \ && apt-get install -y --no-install-recommends \ docker.io=20.10.24+dfsg1-1+b3 \ - libssl-dev=3.0.13-1~deb12u1 \ + libssl-dev=3.0.14-1~deb12u2 \ pkg-config=1.8.1-1 \ unzip=6.0-28 \ wget=${WGET_VERSION} \ software-properties-common=0.99.30-4.1~deb12u1 \ && apt-get install -y --no-install-recommends \ - openjdk-17-jdk=17.0.11+9-1~deb12u1 \ + openjdk-17-jdk=17.0.12+7-2~deb12u1 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -126,12 +126,12 @@ RUN apt-get update \ ca-certificates \ build-essential=12.9 \ # https://security-tracker.debian.org/tracker/CVE-2023-38545 - curl=7.88.1-10+deb12u6 \ + curl=7.88.1-10+deb12u7 \ g++-aarch64-linux-gnu \ g++-x86-64-linux-gnu \ libc6-dev-arm64-cross=2.36-8cross1 \ libclang-dev=1:14.0-55.7~deb12u1 \ - libssl-dev=3.0.13-1~deb12u1 \ + libssl-dev=3.0.14-1~deb12u2 \ pkg-config=1.8.1-1 \ && rm -rf /var/lib/apt/lists/* @@ -177,11 +177,13 @@ RUN USER=root "$HOME/.cargo/bin/cargo" init --lib --name dummy --vcs none . \ && mkdir -p ./jni-export/src \ && mkdir -p ./node-common/src \ && mkdir -p ./state-manager/src \ + && mkdir -p ./p2p/src \ && touch ./core-api-server/src/lib.rs \ && touch ./engine-state-api-server/src/lib.rs \ && touch ./jni-export/src/lib.rs \ && touch ./node-common/src/lib.rs \ - && touch ./state-manager/src/lib.rs + && touch ./state-manager/src/lib.rs \ + && touch ./p2p/src/lib.rs COPY core-rust/Cargo.toml ./ COPY core-rust/Cargo.lock ./ COPY core-rust/core-api-server/Cargo.toml ./core-api-server @@ -189,6 +191,7 @@ COPY core-rust/engine-state-api-server/Cargo.toml ./engine-state-api-server COPY core-rust/jni-export/Cargo.toml ./jni-export COPY core-rust/node-common/Cargo.toml ./node-common COPY core-rust/state-manager/Cargo.toml ./state-manager +COPY core-rust/p2p/Cargo.toml ./p2p COPY docker/build_scripts/cargo_build_by_platform.sh /opt/radixdlt/cargo_build_by_platform.sh @@ -256,9 +259,9 @@ LABEL org.opencontainers.image.authors="devops@radixdlt.com" # - https://packages.debian.org/bookworm/libc6 RUN apt-get update -y \ && apt-get -y --no-install-recommends install \ - openjdk-17-jre-headless=17.0.11+9-1~deb12u1 \ + openjdk-17-jre-headless=17.0.12+7-2~deb12u1 \ # https://security-tracker.debian.org/tracker/CVE-2023-38545 - curl=7.88.1-10+deb12u6 \ + curl=7.88.1-10+deb12u7 \ gettext-base=0.21-12 \ daemontools=1:0.76-8.1 \ # https://security-tracker.debian.org/tracker/CVE-2023-4911 diff --git a/cli-tools/src/main/java/com/radixdlt/shell/RadixShell.java b/cli-tools/src/main/java/com/radixdlt/shell/RadixShell.java index 71a8f662bb..6f1acdddba 100644 --- a/cli-tools/src/main/java/com/radixdlt/shell/RadixShell.java +++ b/cli-tools/src/main/java/com/radixdlt/shell/RadixShell.java @@ -178,7 +178,7 @@ public Node build() throws Exception { dataDir = new File(Files.createTempDirectory("radix-shell-node-").toString()); } - customProperties.build().forEach((k, v) -> properties.set(k, v)); + customProperties.build().forEach(properties::set); properties.set("db.location", dataDir.toString()); diff --git a/common/src/main/java/com/radixdlt/lang/Option.java b/common/src/main/java/com/radixdlt/lang/Option.java index 447c60c769..bf2e1a435c 100644 --- a/common/src/main/java/com/radixdlt/lang/Option.java +++ b/common/src/main/java/com/radixdlt/lang/Option.java @@ -218,6 +218,16 @@ default T or(T replacement) { return fold(Functions::id, () -> replacement); } + /** + * Return current value stored in current instance if current instance is present. If current + * instance is empty then return {@code null}. + * + * @return either value stored in current instance or {@code null} if current instance is empty + */ + default T toNullable() { + return fold(Functions::id, () -> null); + } + /** * Return current value stored in current instance if current instance is present. If current * instance is empty then return value returned by provided supplier. If current instance is not diff --git a/core-rust-bridge/src/main/java/com/radixdlt/p2p/AddressBookEntryDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/p2p/AddressBookEntryDTO.java new file mode 100644 index 0000000000..595625317e --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/p2p/AddressBookEntryDTO.java @@ -0,0 +1,79 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.Set; + +public record AddressBookEntryDTO( + NodeIdDTO nodeId, Option bannedUntil, Set knownAddresses) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + AddressBookEntryDTO.class, + codecs -> StructCodec.fromRecordComponents(AddressBookEntryDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/p2p/NodeIdDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/p2p/NodeIdDTO.java new file mode 100644 index 0000000000..b634b40580 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/p2p/NodeIdDTO.java @@ -0,0 +1,76 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import com.radixdlt.crypto.ECDSASecp256k1PublicKey; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record NodeIdDTO(ECDSASecp256k1PublicKey publicKey) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + NodeIdDTO.class, codecs -> StructCodec.fromRecordComponents(NodeIdDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/p2p/PeerAddressEntryDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/p2p/PeerAddressEntryDTO.java new file mode 100644 index 0000000000..7b2432412b --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/p2p/PeerAddressEntryDTO.java @@ -0,0 +1,124 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.EnumCodec; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.Arrays; +import java.util.Objects; + +public record PeerAddressEntryDTO( + byte[] address, + Option latestConnectionStatus, + Option maybeFailedHandshake) { + public sealed interface ConnectionStatus { + record Success() implements ConnectionStatus {} + + record Failure() implements ConnectionStatus {} + + Success SUCCESS = new Success(); + Failure FAILURE = new Failure(); + } + + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + ConnectionStatus.class, + codecs -> EnumCodec.fromPermittedRecordSubclasses(ConnectionStatus.class, codecs)); + codecMap.register( + PeerAddressEntryDTO.class, + codecs -> StructCodec.fromRecordComponents(PeerAddressEntryDTO.class, codecs)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + return o instanceof PeerAddressEntryDTO that + && Objects.deepEquals(address, that.address) + && Objects.equals(maybeFailedHandshake, that.maybeFailedHandshake) + && Objects.equals(latestConnectionStatus, that.latestConnectionStatus); + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(address), latestConnectionStatus, maybeFailedHandshake); + } + + @Override + public String toString() { + return "PeerAddressEntryDTO{" + + "address=" + + Arrays.toString(address) + + ", latestConnectionStatus=" + + latestConnectionStatus + + ", maybeFailedHandshake=" + + maybeFailedHandshake + + '}'; + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/p2p/RocksDbAddressBookStore.java b/core-rust-bridge/src/main/java/com/radixdlt/p2p/RocksDbAddressBookStore.java new file mode 100644 index 0000000000..29bdce7f49 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/p2p/RocksDbAddressBookStore.java @@ -0,0 +1,158 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import static com.radixdlt.lang.Tuple.*; + +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.radixdlt.environment.NodeRustEnvironment; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.sbor.Natives; +import java.util.List; + +public class RocksDbAddressBookStore { + static { + System.loadLibrary("corerust"); + } + + private static native byte[] removeOne(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] upsertOne(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] reset(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] getAll(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] markAsMigrated( + NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] isMigrated(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + public static RocksDbAddressBookStore create( + Metrics metrics, NodeRustEnvironment nodeRustEnvironment) { + return new RocksDbAddressBookStore(metrics, nodeRustEnvironment); + } + + private RocksDbAddressBookStore(Metrics metrics, NodeRustEnvironment nodeRustEnvironment) { + final var timer = metrics.stateManager().nativeCall(); + removeOneFunc = + Natives.builder(nodeRustEnvironment, RocksDbAddressBookStore::removeOne) + .measure(timer.label(new Metrics.MethodId(RocksDbAddressBookStore.class, "removeOne"))) + .build(new TypeToken<>() {}); + upsertOneFunc = + Natives.builder(nodeRustEnvironment, RocksDbAddressBookStore::upsertOne) + .measure(timer.label(new Metrics.MethodId(RocksDbAddressBookStore.class, "upsertOne"))) + .build(new TypeToken<>() {}); + resetFunc = + Natives.builder(nodeRustEnvironment, RocksDbAddressBookStore::reset) + .measure(timer.label(new Metrics.MethodId(RocksDbAddressBookStore.class, "reset"))) + .build(new TypeToken<>() {}); + getAllFunc = + Natives.builder(nodeRustEnvironment, RocksDbAddressBookStore::getAll) + .measure(timer.label(new Metrics.MethodId(RocksDbAddressBookStore.class, "getAll"))) + .build(new TypeToken<>() {}); + markAsMigratedFunc = + Natives.builder(nodeRustEnvironment, RocksDbAddressBookStore::markAsMigrated) + .measure( + timer.label(new Metrics.MethodId(RocksDbAddressBookStore.class, "markAsMigrated"))) + .build(new TypeToken<>() {}); + isMigratedFunc = + Natives.builder(nodeRustEnvironment, RocksDbAddressBookStore::isMigrated) + .measure(timer.label(new Metrics.MethodId(RocksDbAddressBookStore.class, "isMigrated"))) + .build(new TypeToken<>() {}); + } + + public boolean upsertEntry(AddressBookEntryDTO entry) { + return this.upsertOneFunc.call(entry); + } + + public boolean removeEntry(NodeIdDTO nodeId) { + return this.removeOneFunc.call(nodeId); + } + + public void reset() { + this.resetFunc.call(Tuple0.of()); + } + + public ImmutableList getAllEntries() { + return this.getAllFunc.call(tuple()).stream().collect(ImmutableList.toImmutableList()); + } + + public boolean isMigrated() { + return this.isMigratedFunc.call(tuple()); + } + + public void markAsMigrated() { + this.markAsMigratedFunc.call(tuple()); + } + + private final Natives.Call1 removeOneFunc; + private final Natives.Call1 upsertOneFunc; + private final Natives.Call1 resetFunc; + private final Natives.Call1> getAllFunc; + private final Natives.Call1 isMigratedFunc; + private final Natives.Call1 markAsMigratedFunc; +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/p2p/RocksDbHighPriorityPeersStore.java b/core-rust-bridge/src/main/java/com/radixdlt/p2p/RocksDbHighPriorityPeersStore.java new file mode 100644 index 0000000000..905638144a --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/p2p/RocksDbHighPriorityPeersStore.java @@ -0,0 +1,146 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import static com.radixdlt.lang.Tuple.*; + +import com.google.common.reflect.TypeToken; +import com.radixdlt.environment.NodeRustEnvironment; +import com.radixdlt.lang.Option; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.sbor.Natives; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.List; + +public class RocksDbHighPriorityPeersStore { + static { + System.loadLibrary("corerust"); + } + + public record HighPriorityPeers(List ids) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + HighPriorityPeers.class, + codecs -> StructCodec.fromRecordComponents(HighPriorityPeers.class, codecs)); + } + } + + private static native byte[] upsertAllHighPriorityPeers( + NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] getAllHighPriorityPeers( + NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] resetHighPriorityPeers( + NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + public static RocksDbHighPriorityPeersStore create( + Metrics metrics, NodeRustEnvironment nodeRustEnvironment) { + return new RocksDbHighPriorityPeersStore(metrics, nodeRustEnvironment); + } + + private RocksDbHighPriorityPeersStore(Metrics metrics, NodeRustEnvironment nodeRustEnvironment) { + final var timer = metrics.stateManager().nativeCall(); + upsertAllHighPriorityPeersFunc = + Natives.builder( + nodeRustEnvironment, RocksDbHighPriorityPeersStore::upsertAllHighPriorityPeers) + .measure( + timer.label( + new Metrics.MethodId( + RocksDbHighPriorityPeersStore.class, "upsertAllHighPriorityPeers"))) + .build(new TypeToken<>() {}); + getAllHighPriorityPeersFunc = + Natives.builder(nodeRustEnvironment, RocksDbHighPriorityPeersStore::getAllHighPriorityPeers) + .measure( + timer.label( + new Metrics.MethodId( + RocksDbHighPriorityPeersStore.class, "getAllHighPriorityPeers"))) + .build(new TypeToken<>() {}); + resetFunc = + Natives.builder(nodeRustEnvironment, RocksDbHighPriorityPeersStore::resetHighPriorityPeers) + .measure( + timer.label( + new Metrics.MethodId( + RocksDbHighPriorityPeersStore.class, "resetHighPriorityPeers"))) + .build(new TypeToken<>() {}); + } + + public void storeHighPriorityPeers(List ids) { + this.upsertAllHighPriorityPeersFunc.call(new HighPriorityPeers(ids)); + } + + public List getHighPriorityPeers() { + return this.getAllHighPriorityPeersFunc.call(tuple()).map(HighPriorityPeers::ids).or(List.of()); + } + + public void reset() { + this.resetFunc.call(tuple()); + } + + private final Natives.Call1 upsertAllHighPriorityPeersFunc; + private final Natives.Call1> getAllHighPriorityPeersFunc; + private final Natives.Call1 resetFunc; +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTHeaderDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTHeaderDTO.java new file mode 100644 index 0000000000..50ece65e45 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTHeaderDTO.java @@ -0,0 +1,75 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record BFTHeaderDTO(RoundDTO round, VertexIdDTO vertexId, LedgerHeaderDTO ledgerHeader) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + BFTHeaderDTO.class, codecs -> StructCodec.fromRecordComponents(BFTHeaderDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTValidatorDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTValidatorDTO.java new file mode 100644 index 0000000000..8ec08391f2 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTValidatorDTO.java @@ -0,0 +1,103 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.Arrays; +import java.util.Objects; + +public record BFTValidatorDTO(byte[] power, BFTValidatorIdDTO validatorId) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + BFTValidatorDTO.class, + codecs -> StructCodec.fromRecordComponents(BFTValidatorDTO.class, codecs)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + return o instanceof BFTValidatorDTO that + && Objects.deepEquals(power, that.power) + && Objects.equals(validatorId, that.validatorId); + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(power), validatorId); + } + + @Override + public String toString() { + return "BFTValidatorDTO{" + + "power=" + + Arrays.toString(power) + + ", validatorId=" + + validatorId + + '}'; + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTValidatorIdDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTValidatorIdDTO.java new file mode 100644 index 0000000000..4e8157c6cc --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/BFTValidatorIdDTO.java @@ -0,0 +1,79 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.crypto.ECDSASecp256k1PublicKey; +import com.radixdlt.rev2.ComponentAddress; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +/** Representation of the validator suitable for Java-Rust exchange. */ +public record BFTValidatorIdDTO(ECDSASecp256k1PublicKey key, ComponentAddress validatorAddress) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + BFTValidatorIdDTO.class, + codecs -> StructCodec.fromRecordComponents(BFTValidatorIdDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/HighQCDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/HighQCDTO.java new file mode 100644 index 0000000000..065c3b6085 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/HighQCDTO.java @@ -0,0 +1,79 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record HighQCDTO( + QuorumCertificateDTO highestQC, + QuorumCertificateDTO highestCommittedQC, + Option highestTC) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + HighQCDTO.class, codecs -> StructCodec.fromRecordComponents(HighQCDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/LedgerHeaderDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/LedgerHeaderDTO.java new file mode 100644 index 0000000000..6df20d8ede --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/LedgerHeaderDTO.java @@ -0,0 +1,86 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import com.radixdlt.statecomputer.commit.LedgerHashes; + +public record LedgerHeaderDTO( + long epoch, + RoundDTO round, + long stateVersion, + LedgerHashes hashes, + long consensusParentRoundTimestampMs, + long proposerTimestampMs, + Option nextEpoch, + Option nextProtocolVersion) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + LedgerHeaderDTO.class, + codecs -> StructCodec.fromRecordComponents(LedgerHeaderDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/NextEpochDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/NextEpochDTO.java new file mode 100644 index 0000000000..34968060fd --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/NextEpochDTO.java @@ -0,0 +1,76 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.List; + +public record NextEpochDTO(long epoch, List validators) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + NextEpochDTO.class, codecs -> StructCodec.fromRecordComponents(NextEpochDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/QuorumCertificateDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/QuorumCertificateDTO.java new file mode 100644 index 0000000000..ed63b86657 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/QuorumCertificateDTO.java @@ -0,0 +1,76 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record QuorumCertificateDTO(TimestampedECDSASignaturesDTO signatures, VoteDataDTO voteData) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + QuorumCertificateDTO.class, + codecs -> StructCodec.fromRecordComponents(QuorumCertificateDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/RocksDbSafetyStore.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/RocksDbSafetyStore.java new file mode 100644 index 0000000000..4a08c57135 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/RocksDbSafetyStore.java @@ -0,0 +1,134 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import static com.radixdlt.lang.Tuple.*; + +import com.google.common.reflect.TypeToken; +import com.radixdlt.environment.NodeRustEnvironment; +import com.radixdlt.lang.Option; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.sbor.Natives; + +public class RocksDbSafetyStore { + static { + System.loadLibrary("corerust"); + } + + private static native byte[] upsert(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] get(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] markAsMigrated( + NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + private static native byte[] isMigrated(NodeRustEnvironment nodeRustEnvironment, byte[] payload); + + public static RocksDbSafetyStore create( + Metrics metrics, NodeRustEnvironment nodeRustEnvironment) { + return new RocksDbSafetyStore(metrics, nodeRustEnvironment); + } + + private RocksDbSafetyStore(Metrics metrics, NodeRustEnvironment nodeRustEnvironment) { + final var timer = metrics.stateManager().nativeCall(); + upsertFunc = + Natives.builder(nodeRustEnvironment, RocksDbSafetyStore::upsert) + .measure(timer.label(new Metrics.MethodId(RocksDbSafetyStore.class, "upsert"))) + .build(new TypeToken<>() {}); + getFunc = + Natives.builder(nodeRustEnvironment, RocksDbSafetyStore::get) + .measure(timer.label(new Metrics.MethodId(RocksDbSafetyStore.class, "get"))) + .build(new TypeToken<>() {}); + markAsMigratedFunc = + Natives.builder(nodeRustEnvironment, RocksDbSafetyStore::markAsMigrated) + .measure(timer.label(new Metrics.MethodId(RocksDbSafetyStore.class, "markAsMigrated"))) + .build(new TypeToken<>() {}); + isMigratedFunc = + Natives.builder(nodeRustEnvironment, RocksDbSafetyStore::isMigrated) + .measure(timer.label(new Metrics.MethodId(RocksDbSafetyStore.class, "isMigrated"))) + .build(new TypeToken<>() {}); + } + + public void upsert(SafetyStateDTO state) { + this.upsertFunc.call(state); + } + + public Option get() { + return this.getFunc.call(tuple()); + } + + public boolean isMigrated() { + return this.isMigratedFunc.call(tuple()); + } + + public void markAsMigrated() { + this.markAsMigratedFunc.call(tuple()); + } + + private final Natives.Call1 upsertFunc; + private final Natives.Call1> getFunc; + private final Natives.Call1 isMigratedFunc; + private final Natives.Call1 markAsMigratedFunc; +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/RoundDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/RoundDTO.java new file mode 100644 index 0000000000..f26298b5b1 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/RoundDTO.java @@ -0,0 +1,75 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record RoundDTO(long round) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + RoundDTO.class, codecs -> StructCodec.fromRecordComponents(RoundDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/SafetyStateDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/SafetyStateDTO.java new file mode 100644 index 0000000000..ca3e216c06 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/SafetyStateDTO.java @@ -0,0 +1,78 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record SafetyStateDTO( + BFTValidatorIdDTO validatorId, RoundDTO round, Option lastVote) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + SafetyStateDTO.class, + codecs -> StructCodec.fromRecordComponents(SafetyStateDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/TimeoutCertificateDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/TimeoutCertificateDTO.java new file mode 100644 index 0000000000..58d735d537 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/TimeoutCertificateDTO.java @@ -0,0 +1,77 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record TimeoutCertificateDTO( + long epoch, RoundDTO round, TimestampedECDSASignaturesDTO signatures) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + TimeoutCertificateDTO.class, + codecs -> StructCodec.fromRecordComponents(TimeoutCertificateDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/TimestampedECDSASignatureDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/TimestampedECDSASignatureDTO.java new file mode 100644 index 0000000000..d6f5fb87a9 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/TimestampedECDSASignatureDTO.java @@ -0,0 +1,77 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.crypto.ECDSASecp256k1Signature; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record TimestampedECDSASignatureDTO(long timestamp, ECDSASecp256k1Signature signature) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + TimestampedECDSASignatureDTO.class, + codecs -> StructCodec.fromRecordComponents(TimestampedECDSASignatureDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/TimestampedECDSASignaturesDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/TimestampedECDSASignaturesDTO.java new file mode 100644 index 0000000000..d5cdc06e77 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/TimestampedECDSASignaturesDTO.java @@ -0,0 +1,78 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.Map; + +public record TimestampedECDSASignaturesDTO( + Map nodeToTimestampedSignature) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + TimestampedECDSASignaturesDTO.class, + codecs -> StructCodec.fromRecordComponents(TimestampedECDSASignaturesDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/VertexIdDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/VertexIdDTO.java new file mode 100644 index 0000000000..74a7e9e1d5 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/VertexIdDTO.java @@ -0,0 +1,109 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.Arrays; + +public record VertexIdDTO(byte[] idBytes) { + public VertexIdDTO { + if (idBytes == null) { + throw new IllegalArgumentException("idBytes is null"); + } + + if (idBytes.length != 32) { + throw new IllegalArgumentException("idBytes has invalid length: " + idBytes.length); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + return o instanceof VertexIdDTO that && Arrays.equals(idBytes, that.idBytes); + } + + @Override + public int hashCode() { + return Arrays.hashCode(idBytes); + } + + @Override + public String toString() { + return "VertexIdDTO{" + "idBytes=" + Arrays.toString(idBytes) + '}'; + } + + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + VertexIdDTO.class, + codecs -> + StructCodec.with( + VertexIdDTO::new, + codecs.of(byte[].class), + (t, encoder) -> encoder.encode(t.idBytes()))); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/VoteDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/VoteDTO.java new file mode 100644 index 0000000000..9f5752a756 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/VoteDTO.java @@ -0,0 +1,83 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.crypto.ECDSASecp256k1Signature; +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record VoteDTO( + BFTValidatorIdDTO author, + HighQCDTO highQC, + VoteDataDTO voteData, + long timestamp, + ECDSASecp256k1Signature signature, + Option timeoutSignature) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + VoteDTO.class, codecs -> StructCodec.fromRecordComponents(VoteDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/safety/VoteDataDTO.java b/core-rust-bridge/src/main/java/com/radixdlt/safety/VoteDataDTO.java new file mode 100644 index 0000000000..01e8d8d8f3 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/safety/VoteDataDTO.java @@ -0,0 +1,77 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import com.radixdlt.lang.Option; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; + +public record VoteDataDTO( + BFTHeaderDTO proposed, BFTHeaderDTO parent, Option committed) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + VoteDataDTO.class, codecs -> StructCodec.fromRecordComponents(VoteDataDTO.class, codecs)); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/sbor/NodeSborCodecs.java b/core-rust-bridge/src/main/java/com/radixdlt/sbor/NodeSborCodecs.java index b5228878a9..aa93a9e209 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/sbor/NodeSborCodecs.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/sbor/NodeSborCodecs.java @@ -75,10 +75,15 @@ import com.radixdlt.mempool.ProposalTransactionsRequest; import com.radixdlt.mempool.RustMempoolConfig; import com.radixdlt.message.*; +import com.radixdlt.p2p.AddressBookEntryDTO; +import com.radixdlt.p2p.NodeIdDTO; +import com.radixdlt.p2p.PeerAddressEntryDTO; +import com.radixdlt.p2p.RocksDbHighPriorityPeersStore.HighPriorityPeers; import com.radixdlt.prometheus.LedgerStatus; import com.radixdlt.prometheus.RecentSelfProposalMissStatistic; import com.radixdlt.protocol.*; import com.radixdlt.rev2.*; +import com.radixdlt.safety.*; import com.radixdlt.sbor.codec.Codec; import com.radixdlt.sbor.codec.CodecMap; import com.radixdlt.sbor.codec.StructCodec; @@ -213,6 +218,27 @@ public static void registerCodecsWithCodecMap(CodecMap codecMap) { StateTreeGcConfig.registerCodec(codecMap); LedgerProofsGcConfig.registerCodec(codecMap); LedgerSyncLimitsConfig.registerCodec(codecMap); + + BFTHeaderDTO.registerCodec(codecMap); + BFTValidatorDTO.registerCodec(codecMap); + BFTValidatorIdDTO.registerCodec(codecMap); + HighQCDTO.registerCodec(codecMap); + HighPriorityPeers.registerCodec(codecMap); + LedgerHeaderDTO.registerCodec(codecMap); + NextEpochDTO.registerCodec(codecMap); + QuorumCertificateDTO.registerCodec(codecMap); + RoundDTO.registerCodec(codecMap); + SafetyStateDTO.registerCodec(codecMap); + PeerAddressEntryDTO.registerCodec(codecMap); + TimeoutCertificateDTO.registerCodec(codecMap); + TimestampedECDSASignatureDTO.registerCodec(codecMap); + TimestampedECDSASignaturesDTO.registerCodec(codecMap); + VertexIdDTO.registerCodec(codecMap); + VoteDataDTO.registerCodec(codecMap); + VoteDTO.registerCodec(codecMap); + + AddressBookEntryDTO.registerCodec(codecMap); + NodeIdDTO.registerCodec(codecMap); } public static void registerCodecsForExistingTypes(CodecMap codecMap) { diff --git a/core-rust-bridge/src/test/java/com/radixdlt/helper/NodeRustEnvironmentBuilder.java b/core-rust-bridge/src/test/java/com/radixdlt/helper/NodeRustEnvironmentBuilder.java new file mode 100644 index 0000000000..5e7eeca4d6 --- /dev/null +++ b/core-rust-bridge/src/test/java/com/radixdlt/helper/NodeRustEnvironmentBuilder.java @@ -0,0 +1,109 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.helper; + +import com.radixdlt.environment.*; +import com.radixdlt.lang.Option; +import com.radixdlt.mempool.RustMempoolConfig; +import com.radixdlt.protocol.ProtocolConfig; +import com.radixdlt.rev2.NetworkDefinition; +import com.radixdlt.transaction.LedgerSyncLimitsConfig; + +public final class NodeRustEnvironmentBuilder { + private NodeRustEnvironmentBuilder() { + throw new IllegalStateException("Can't construct"); + } + + public static NodeRustEnvironment createNodeRustEnvironment(String dbPath) { + final var mempoolMaxTotalTransactionsSize = 10 * 1024 * 1024; + final var mempoolMaxTransactionCount = 20; + final var stateManagerDbConfig = new DatabaseBackendConfig(dbPath); + + final var config = + new StateManagerConfig( + NetworkDefinition.INT_TEST_NET, + Option.some( + new RustMempoolConfig(mempoolMaxTotalTransactionsSize, mempoolMaxTransactionCount)), + Option.none(), + stateManagerDbConfig, + new DatabaseConfig(false, false, false, false), + LoggingConfig.getDefault(), + StateTreeGcConfig.forTesting(), + LedgerProofsGcConfig.forTesting(), + LedgerSyncLimitsConfig.defaults(), + ProtocolConfig.testingDefault(), + false, + ScenariosExecutionConfig.NONE); + + return new NodeRustEnvironment( + tx -> {}, // A no-op dispatcher of transactions to be relayed. + () -> {}, // A no-op fatal panic handler. Please note that a JNI-invoking test (like this + // one) will observe + // panics as runtime exceptions propagated up the stack (through JNI), which will fail the + // test + // gracefully anyway. + config); + } +} diff --git a/core-rust-bridge/src/test/java/com/radixdlt/p2p/RocksDbAddressBookStoreTest.java b/core-rust-bridge/src/test/java/com/radixdlt/p2p/RocksDbAddressBookStoreTest.java new file mode 100644 index 0000000000..7e697f381c --- /dev/null +++ b/core-rust-bridge/src/test/java/com/radixdlt/p2p/RocksDbAddressBookStoreTest.java @@ -0,0 +1,233 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import static com.radixdlt.lang.Option.none; +import static com.radixdlt.lang.Option.some; +import static org.junit.Assert.*; + +import com.radixdlt.crypto.ECKeyPair; +import com.radixdlt.helper.NodeRustEnvironmentBuilder; +import com.radixdlt.lang.Option; +import com.radixdlt.monitoring.MetricsInitializer; +import com.radixdlt.p2p.PeerAddressEntryDTO.ConnectionStatus; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class RocksDbAddressBookStoreTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + private static final Random RANDOM = new Random(); + + @Test + public void test_address_book_can_be_marked_as_migrated() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var addressBookStore = + RocksDbAddressBookStore.create( + new MetricsInitializer().initialize(), nodeRustEnvironment); + + assertFalse(addressBookStore.isMigrated()); + + addressBookStore.markAsMigrated(); + + assertTrue(addressBookStore.isMigrated()); + } + } + + @Test + public void test_address_book_entries_can_be_saved_and_restored() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var addressBookStore = + RocksDbAddressBookStore.create( + new MetricsInitializer().initialize(), nodeRustEnvironment); + + // New store is empty + var empty = addressBookStore.getAllEntries(); + assertTrue(empty.isEmpty()); + + // Ensure keys are repeatable to make test deterministic + var entry1 = newAddressBookEntry(1); + + addressBookStore.upsertEntry(entry1); + + // Store now contains one entry + var allEntries = addressBookStore.getAllEntries(); + assertEquals(1L, allEntries.size()); + assertEquals(entry1, allEntries.get(0)); + + // Ensure keys are repeatable to make test deterministic + var entry2 = newAddressBookEntry(2); + + // Add another entry + addressBookStore.upsertEntry(entry2); + + allEntries = addressBookStore.getAllEntries(); + assertEquals(2L, allEntries.size()); + assertEquals(entry1, allEntries.get(0)); + assertEquals(entry2, allEntries.get(1)); + } + } + + @Test + public void test_address_book_entry_can_be_added_and_removed() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var addressBookStore = + RocksDbAddressBookStore.create( + new MetricsInitializer().initialize(), nodeRustEnvironment); + + // New store is empty + var empty = addressBookStore.getAllEntries(); + assertTrue(empty.isEmpty()); + + // Ensure keys are repeatable to make test deterministic + var entry1 = newAddressBookEntry(1); + var entry2 = newAddressBookEntry(2); + + addressBookStore.upsertEntry(entry1); + addressBookStore.upsertEntry(entry2); + + // Check that entries were added + var allEntries = addressBookStore.getAllEntries(); + assertEquals(2L, allEntries.size()); + assertEquals(entry1, allEntries.get(0)); + assertEquals(entry2, allEntries.get(1)); + + // Remove entry1 + var removed = addressBookStore.removeEntry(entry1.nodeId()); + assertTrue(removed); + + // Check that entry1 was removed + allEntries = addressBookStore.getAllEntries(); + assertEquals(1L, allEntries.size()); + assertEquals(entry2, allEntries.get(0)); + } + } + + @Test + public void test_address_book_can_be_reset() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var addressBookStore = + RocksDbAddressBookStore.create( + new MetricsInitializer().initialize(), nodeRustEnvironment); + + // New store is empty + var empty = addressBookStore.getAllEntries(); + assertTrue(empty.isEmpty()); + + // Ensure keys are repeatable to make test deterministic + var entry1 = newAddressBookEntry(1); + var entry2 = newAddressBookEntry(2); + + addressBookStore.upsertEntry(entry1); + addressBookStore.upsertEntry(entry2); + + // Check that entries were added + var allEntries = addressBookStore.getAllEntries(); + assertEquals(2L, allEntries.size()); + assertEquals(entry1, allEntries.get(0)); + assertEquals(entry2, allEntries.get(1)); + + // Reset store + addressBookStore.reset(); + + // Check that entry1 was removed + empty = addressBookStore.getAllEntries(); + assertTrue(empty.isEmpty()); + } + } + + private static AddressBookEntryDTO newAddressBookEntry(int id) { + return new AddressBookEntryDTO( + new NodeIdDTO(ECKeyPair.fromSeed(new byte[] {(byte) id}).getPublicKey()), + RANDOM.nextBoolean() ? some(RANDOM.nextLong()) : none(), + peerAddresses()); + } + + private static Set peerAddresses() { + return IntStream.range(0, RANDOM.nextInt(3)) + .mapToObj(__ -> newPeerAddressEntry()) + .collect(Collectors.toSet()); + } + + private static PeerAddressEntryDTO newPeerAddressEntry() { + var pubKey = ECKeyPair.generateNew().getPublicKey().getBytes(); + return new PeerAddressEntryDTO(pubKey, connectionStatus(), Option.some(RANDOM.nextLong())); + } + + private static Option connectionStatus() { + return RANDOM.nextBoolean() + ? Option.some(RANDOM.nextBoolean() ? ConnectionStatus.SUCCESS : ConnectionStatus.FAILURE) + : Option.none(); + } +} diff --git a/core-rust-bridge/src/test/java/com/radixdlt/p2p/RocksDbHighPriorityPeersStoreTest.java b/core-rust-bridge/src/test/java/com/radixdlt/p2p/RocksDbHighPriorityPeersStoreTest.java new file mode 100644 index 0000000000..80a00c4235 --- /dev/null +++ b/core-rust-bridge/src/test/java/com/radixdlt/p2p/RocksDbHighPriorityPeersStoreTest.java @@ -0,0 +1,125 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p; + +import static org.junit.Assert.*; + +import com.radixdlt.crypto.ECKeyPair; +import com.radixdlt.helper.NodeRustEnvironmentBuilder; +import com.radixdlt.monitoring.MetricsInitializer; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class RocksDbHighPriorityPeersStoreTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void test_high_priority_peers_can_be_saved_and_restored() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var highPriorityPeersStore = + RocksDbHighPriorityPeersStore.create( + new MetricsInitializer().initialize(), nodeRustEnvironment); + + // New store is empty + var empty = highPriorityPeersStore.getHighPriorityPeers(); + assertTrue(empty.isEmpty()); + + var inputList1 = List.of(newNodeId(), newNodeId(), newNodeId()); + + // Store new list + highPriorityPeersStore.storeHighPriorityPeers(inputList1); + + // Retrieve same list back + var peers = highPriorityPeersStore.getHighPriorityPeers(); + assertEquals(3L, peers.size()); + assertEquals(inputList1, peers); + + // Overwrite with a new list + var inputList2 = List.of(newNodeId(), newNodeId(), newNodeId()); + + // Ensure lists are different + assertNotEquals(inputList1, inputList2); + + // Store new list + highPriorityPeersStore.storeHighPriorityPeers(inputList2); + + peers = highPriorityPeersStore.getHighPriorityPeers(); + assertEquals(3L, peers.size()); + assertEquals(inputList2, peers); + + // Reset store + highPriorityPeersStore.reset(); + empty = highPriorityPeersStore.getHighPriorityPeers(); + assertTrue(empty.isEmpty()); + } + } + + private static NodeIdDTO newNodeId() { + return new NodeIdDTO(ECKeyPair.generateNew().getPublicKey()); + } +} diff --git a/core-rust-bridge/src/test/java/com/radixdlt/safety/RocksDbSafetyStoreTest.java b/core-rust-bridge/src/test/java/com/radixdlt/safety/RocksDbSafetyStoreTest.java new file mode 100644 index 0000000000..ae28393224 --- /dev/null +++ b/core-rust-bridge/src/test/java/com/radixdlt/safety/RocksDbSafetyStoreTest.java @@ -0,0 +1,127 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.safety; + +import static org.junit.Assert.*; + +import com.google.common.primitives.Bytes; +import com.radixdlt.crypto.ECKeyPair; +import com.radixdlt.helper.NodeRustEnvironmentBuilder; +import com.radixdlt.lang.Option; +import com.radixdlt.monitoring.MetricsInitializer; +import com.radixdlt.rev2.ComponentAddress; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class RocksDbSafetyStoreTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void test_safety_store_can_be_marked_as_migrated() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var safetyStore = + RocksDbSafetyStore.create(new MetricsInitializer().initialize(), nodeRustEnvironment); + + assertFalse(safetyStore.isMigrated()); + + safetyStore.markAsMigrated(); + + assertTrue(safetyStore.isMigrated()); + } + } + + @Test + public void test_safety_state_can_be_saved_and_restored() throws Exception { + try (var nodeRustEnvironment = + NodeRustEnvironmentBuilder.createNodeRustEnvironment(folder.newFolder().getPath())) { + var safetyStore = + RocksDbSafetyStore.create(new MetricsInitializer().initialize(), nodeRustEnvironment); + var address = + new ComponentAddress( + Bytes.toArray( + Collections.nCopies( + ComponentAddress.BYTE_LENGTH, + ComponentAddress.VALIDATOR_COMPONENT_ADDRESS_ENTITY_ID))); + + var originalSafetyState = + new SafetyStateDTO( + new BFTValidatorIdDTO(ECKeyPair.generateNew().getPublicKey(), address), + new RoundDTO(10L), + Option.none()); + + var empty = safetyStore.get(); + assertTrue(empty.isEmpty()); + + safetyStore.upsert(originalSafetyState); + var present = safetyStore.get(); + + assertTrue(present.isPresent()); + assertEquals(originalSafetyState, present.orElseThrow()); + } + } +} diff --git a/core-rust/Cargo.lock b/core-rust/Cargo.lock index 5a34f9076b..9c1b774564 100644 --- a/core-rust/Cargo.lock +++ b/core-rust/Cargo.lock @@ -1299,6 +1299,7 @@ version = "0.1.0" dependencies = [ "bech32", "blake2", + "itertools", "jni", "opentelemetry", "opentelemetry-jaeger", @@ -1312,6 +1313,7 @@ dependencies = [ "radix-substate-store-interface", "radix-substate-store-queries", "radix-transactions", + "rocksdb", "sbor", "tokio", "tokio-util", @@ -1496,6 +1498,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p2p" +version = "0.1.0" +dependencies = [ + "jni", + "node-common", + "radix-common", + "sbor", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -2384,6 +2396,7 @@ dependencies = [ "jni", "lru", "node-common", + "p2p", "prometheus", "radix-common", "radix-engine", @@ -2395,7 +2408,6 @@ dependencies = [ "radix-transaction-scenarios", "radix-transactions", "rand 0.8.5", - "rocksdb", "sbor", "slotmap", "tempfile", diff --git a/core-rust/core-api-server/src/core_api/conversions/lts.rs b/core-rust/core-api-server/src/core_api/conversions/lts.rs index d9dfe70638..8d3bae4244 100644 --- a/core-rust/core-api-server/src/core_api/conversions/lts.rs +++ b/core-rust/core-api-server/src/core_api/conversions/lts.rs @@ -1,5 +1,6 @@ use crate::engine_prelude::*; -use state_manager::rocks_db::{ReadableRocks, StateManagerDatabase}; +use node_common::store::rocks_db::ReadableRocks; +use state_manager::store::rocks_db::StateManagerDatabase; use state_manager::store::traits::SubstateNodeAncestryStore; use state_manager::{ CommittedTransactionIdentifiers, LedgerTransactionOutcome, LocalTransactionReceipt, diff --git a/core-rust/core-api-server/src/core_api/conversions/receipt.rs b/core-rust/core-api-server/src/core_api/conversions/receipt.rs index 982afd5ba7..9703b26bee 100644 --- a/core-rust/core-api-server/src/core_api/conversions/receipt.rs +++ b/core-rust/core-api-server/src/core_api/conversions/receipt.rs @@ -4,7 +4,8 @@ use super::addressing::*; use crate::core_api::*; use crate::engine_prelude::*; -use state_manager::rocks_db::{ReadableRocks, StateManagerDatabase}; +use node_common::store::rocks_db::ReadableRocks; +use state_manager::store::rocks_db::StateManagerDatabase; use state_manager::{ ApplicationEvent, BySubstate, DetailedTransactionOutcome, LedgerStateChanges, LocalTransactionReceipt, PartitionChangeAction, PartitionReference, SubstateChangeAction, diff --git a/core-rust/core-api-server/src/core_api/handlers/state_consensus_manager.rs b/core-rust/core-api-server/src/core_api/handlers/state_consensus_manager.rs index e487aa5b72..e040ea8fde 100644 --- a/core-rust/core-api-server/src/core_api/handlers/state_consensus_manager.rs +++ b/core-rust/core-api-server/src/core_api/handlers/state_consensus_manager.rs @@ -1,8 +1,9 @@ use crate::core_api::*; use crate::engine_prelude::*; +use node_common::store::rocks_db::ReadableRocks; use state_manager::protocol::ProtocolVersionName; -use state_manager::rocks_db::{ReadableRocks, StateManagerDatabase}; +use state_manager::store::rocks_db::StateManagerDatabase; use std::ops::Deref; #[tracing::instrument(skip(state))] diff --git a/core-rust/core-api-server/src/core_api/handlers/stream_proofs.rs b/core-rust/core-api-server/src/core_api/handlers/stream_proofs.rs index 45da8d8f5a..a3565061b3 100644 --- a/core-rust/core-api-server/src/core_api/handlers/stream_proofs.rs +++ b/core-rust/core-api-server/src/core_api/handlers/stream_proofs.rs @@ -1,7 +1,8 @@ use crate::core_api::*; use crate::engine_prelude::*; -use state_manager::rocks_db::{ReadableRocks, StateManagerDatabase}; +use node_common::store::rocks_db::ReadableRocks; +use state_manager::store::rocks_db::StateManagerDatabase; use state_manager::store::traits::*; use state_manager::{LedgerProof, LedgerProofOrigin, StateVersion}; diff --git a/core-rust/core-api-server/src/core_api/handlers/stream_transactions.rs b/core-rust/core-api-server/src/core_api/handlers/stream_transactions.rs index 5b18e355eb..8a5caabefa 100644 --- a/core-rust/core-api-server/src/core_api/handlers/stream_transactions.rs +++ b/core-rust/core-api-server/src/core_api/handlers/stream_transactions.rs @@ -5,7 +5,8 @@ use std::ops::Deref; use crate::core_api::*; -use state_manager::rocks_db::{ReadableRocks, StateManagerDatabase}; +use node_common::store::rocks_db::ReadableRocks; +use state_manager::store::rocks_db::StateManagerDatabase; use state_manager::store::traits::*; use state_manager::transaction::*; use state_manager::{ diff --git a/core-rust/core-api-server/src/core_api/handlers/transaction_preview.rs b/core-rust/core-api-server/src/core_api/handlers/transaction_preview.rs index 4bbe016050..0d8608ad7c 100644 --- a/core-rust/core-api-server/src/core_api/handlers/transaction_preview.rs +++ b/core-rust/core-api-server/src/core_api/handlers/transaction_preview.rs @@ -1,7 +1,7 @@ use crate::core_api::*; use crate::engine_prelude::*; -use state_manager::rocks_db::ActualStateManagerDatabase; +use state_manager::store::rocks_db::ActualStateManagerDatabase; use state_manager::transaction::ProcessedPreviewResult; use state_manager::{ExecutionFeeData, LocalTransactionReceipt, PreviewRequest}; diff --git a/core-rust/core-api-server/src/core_api/helpers.rs b/core-rust/core-api-server/src/core_api/helpers.rs index e64ea4d53d..6d68a4e62a 100644 --- a/core-rust/core-api-server/src/core_api/helpers.rs +++ b/core-rust/core-api-server/src/core_api/helpers.rs @@ -1,6 +1,7 @@ use crate::engine_prelude::*; +use node_common::store::rocks_db::ReadableRocks; use serde::Serialize; -use state_manager::rocks_db::{ReadableRocks, StateManagerDatabase}; +use state_manager::store::rocks_db::StateManagerDatabase; use state_manager::store::traits::*; use state_manager::LedgerHeader; use std::io::Write; diff --git a/core-rust/node-common/Cargo.toml b/core-rust/node-common/Cargo.toml index 428b7c2087..d026182468 100644 --- a/core-rust/node-common/Cargo.toml +++ b/core-rust/node-common/Cargo.toml @@ -15,6 +15,7 @@ radix-substate-store-queries = { workspace = true } radix-rust = { workspace = true } # Non-Radix Engine Dependencies: +itertools = { workspace = true } jni = { workspace = true } tracing = { workspace = true } tokio = { workspace = true } @@ -28,3 +29,4 @@ tracing-opentelemetry = { version = "=0.18.0" } tracing-subscriber = { version = "=0.3.17" } opentelemetry = { version = "=0.18.0", default-features = false, features = ["rt-tokio", "trace"] } opentelemetry-jaeger = { version = "=0.17.0", features = ["rt-tokio"] } +rocksdb = { version = "=0.21.0" } diff --git a/core-rust/node-common/src/lib.rs b/core-rust/node-common/src/lib.rs index 1e782f4db0..2f898a4b4b 100644 --- a/core-rust/node-common/src/lib.rs +++ b/core-rust/node-common/src/lib.rs @@ -70,7 +70,9 @@ pub mod jni; pub mod locks; pub mod metrics; pub mod scheduler; +pub mod store; pub mod utils; +pub use rocksdb; pub(crate) mod engine_prelude { pub use radix_common::prelude::*; diff --git a/core-rust/node-common/src/store/mod.rs b/core-rust/node-common/src/store/mod.rs new file mode 100644 index 0000000000..561e3addfa --- /dev/null +++ b/core-rust/node-common/src/store/mod.rs @@ -0,0 +1,2 @@ +pub mod rocks_db; +pub mod typed_cf_api; diff --git a/core-rust/node-common/src/store/rocks_db.rs b/core-rust/node-common/src/store/rocks_db.rs new file mode 100644 index 0000000000..9035adb393 --- /dev/null +++ b/core-rust/node-common/src/store/rocks_db.rs @@ -0,0 +1,267 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::engine_prelude::*; +use rocksdb::checkpoint::Checkpoint; +use rocksdb::{ + AsColumnFamilyRef, ColumnFamily, DBPinnableSlice, IteratorMode, Snapshot, WriteBatch, DB, +}; + +use std::path::PathBuf; + +/// A redefined RocksDB's "key and value bytes" tuple (the original one lives in a private module). +pub type KVBytes = (Box<[u8]>, Box<[u8]>); + +/// A trait capturing the common read methods present both in a "direct" RocksDB instance and in its +/// snapshots. +/// +/// The library we use (a thin C wrapper, really) does not introduce this trivial and natural trait +/// itself, while we desperately need it to abstract the DB-reading code from the actual source of +/// data. +/// +/// A note on changed error handling: +/// The original methods typically return [`Result`]s. Our trait assumes panics instead, since we +/// treat all database access errors as fatal anyways. +pub trait ReadableRocks { + /// Resolves the column family by name. + fn cf_handle(&self, name: &str) -> &ColumnFamily; + + /// Starts iteration over key-value pairs, according to the given [`IteratorMode`]. + fn iterator_cf( + &self, + cf: &impl AsColumnFamilyRef, + mode: IteratorMode, + ) -> Box + '_>; + + /// Gets a single value by key. + fn get_pinned_cf( + &self, + cf: &impl AsColumnFamilyRef, + key: impl AsRef<[u8]>, + ) -> Option; + + /// Gets multiple values by keys. + /// + /// Syntax note: + /// The `<'a>` here is not special at all: it could technically be 100% inferred. Just the + /// compiler feature allowing to skip it from within the `` is not yet stable. + /// TODO(when the rustc feature mentioned above becomes stable): get rid of the `<'a>`. + fn multi_get_cf<'a>( + &'a self, + keys: impl IntoIterator)>, + ) -> Vec>>; +} + +/// A write-supporting extension of the [`ReadableRocks`]. +/// +/// Naturally, it is expected that only a "direct" RocksDB instance can implement this one. +pub trait WriteableRocks: ReadableRocks { + /// Atomically writes the given batch of updates. + fn write(&self, batch: WriteBatch); + + /// Returns a snapshot of the current state. + fn snapshot(&self) -> SnapshotRocks; +} + +/// A [`ReadableRocks`] instance opened as secondary instance. +pub trait SecondaryRocks: ReadableRocks { + /// Tries to catch up with the primary by reading as much as possible from the + /// log files. + fn try_catchup_with_primary(&self); +} + +/// RocksDB checkpoint support. +pub trait CheckpointableRocks { + fn create_checkpoint(&self, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error>; +} + +/// Direct RocksDB instance. +pub struct DirectRocks { + pub db: DB, +} + +impl ReadableRocks for DirectRocks { + fn cf_handle(&self, name: &str) -> &ColumnFamily { + self.db.cf_handle(name).expect(name) + } + + fn iterator_cf( + &self, + cf: &impl AsColumnFamilyRef, + mode: IteratorMode, + ) -> Box + '_> { + Box::new( + self.db + .iterator_cf(cf, mode) + .map(|result| result.expect("reading from DB iterator")), + ) + } + + fn get_pinned_cf( + &self, + cf: &impl AsColumnFamilyRef, + key: impl AsRef<[u8]>, + ) -> Option { + self.db.get_pinned_cf(cf, key).expect("DB get by key") + } + + fn multi_get_cf<'a>( + &'a self, + keys: impl IntoIterator)>, + ) -> Vec>> { + self.db + .multi_get_cf(keys) + .into_iter() + .map(|result| result.expect("batch DB get by key")) + .collect() + } +} + +impl WriteableRocks for DirectRocks { + fn write(&self, batch: WriteBatch) { + self.db.write(batch).expect("DB write batch"); + } + + fn snapshot(&self) -> SnapshotRocks { + SnapshotRocks { + db: &self.db, + snapshot: self.db.snapshot(), + } + } +} + +impl SecondaryRocks for DirectRocks { + fn try_catchup_with_primary(&self) { + self.db + .try_catch_up_with_primary() + .expect("secondary DB catchup"); + } +} + +impl CheckpointableRocks for DirectRocks { + fn create_checkpoint(&self, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error> { + create_checkpoint(&self.db, checkpoint_path) + } +} + +impl<'db> CheckpointableRocks for SnapshotRocks<'db> { + fn create_checkpoint(&self, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error> { + create_checkpoint(self.db, checkpoint_path) + } +} + +fn create_checkpoint(db: &DB, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error> { + let checkpoint = Checkpoint::new(db)?; + checkpoint.create_checkpoint(checkpoint_path)?; + Ok(()) +} + +/// Snapshot of RocksDB. +/// +/// Implementation note: +/// The original [`DB`] reference is interestingly kept internally by the [`Snapshot`] as well. +/// However, we need direct access to it for the [`Self::cf_handle()`] reasons. +pub struct SnapshotRocks<'db> { + db: &'db DB, + snapshot: Snapshot<'db>, +} + +impl<'db> ReadableRocks for SnapshotRocks<'db> { + fn cf_handle(&self, name: &str) -> &ColumnFamily { + self.db.cf_handle(name).expect(name) + } + + fn iterator_cf( + &self, + cf: &impl AsColumnFamilyRef, + mode: IteratorMode, + ) -> Box + '_> { + Box::new( + self.snapshot + .iterator_cf(cf, mode) + .map(|result| result.expect("reading from snapshot DB iterator")), + ) + } + + fn get_pinned_cf( + &self, + cf: &impl AsColumnFamilyRef, + key: impl AsRef<[u8]>, + ) -> Option { + self.snapshot + .get_pinned_cf(cf, key) + .expect("snapshot DB get by key") + } + + fn multi_get_cf<'a>( + &'a self, + keys: impl IntoIterator)>, + ) -> Vec>> { + self.snapshot + .multi_get_cf(keys) + .into_iter() + .map(|result| result.expect("batch snapshot DB get by key")) + .collect() + } +} diff --git a/core-rust/state-manager/src/store/typed_cf_api.rs b/core-rust/node-common/src/store/typed_cf_api.rs similarity index 99% rename from core-rust/state-manager/src/store/typed_cf_api.rs rename to core-rust/node-common/src/store/typed_cf_api.rs index 3d6efea5c3..7bf537418f 100644 --- a/core-rust/state-manager/src/store/typed_cf_api.rs +++ b/core-rust/node-common/src/store/typed_cf_api.rs @@ -238,6 +238,14 @@ impl<'r, 'w, KC: BoundedDbCodec, CF: TypedCf, R: WriteableRocks> self.cf.key_codec.upper_bound_encoding(), ); } + + /// Retrieves all entries. + pub fn get_all(&self) -> Vec { + self.rocks + .iterator_cf(self.cf.handle, IteratorMode::Start) + .map(|(_, value)| self.cf.value_codec.decode(value.as_ref())) + .collect() + } } impl<'r, 'w, KC: GroupPreservingDbCodec, CF: TypedCf, R: WriteableRocks> diff --git a/core-rust/p2p/Cargo.toml b/core-rust/p2p/Cargo.toml new file mode 100644 index 0000000000..7045c14441 --- /dev/null +++ b/core-rust/p2p/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "p2p" +version = "0.1.0" +edition = "2021" + +[dependencies] +node-common = { path = "../node-common" } + +sbor = { workspace = true } +radix-common = { workspace = true } + +# Non-Radix Engine Dependencies: +jni = { workspace = true } diff --git a/core-rust/p2p/src/address_book_components.rs b/core-rust/p2p/src/address_book_components.rs new file mode 100644 index 0000000000..1bec0b8497 --- /dev/null +++ b/core-rust/p2p/src/address_book_components.rs @@ -0,0 +1,119 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::components; +use crate::engine_prelude::*; +use crate::engine_prelude::{ScryptoCategorize, ScryptoDecode, ScryptoEncode}; +use sbor::define_single_versioned; + +/// Timestamp of the various peer-related events +// At present, it's just an alias for i64. Later we may want to replace it with struct using crono crate and +// do something like shown below to transparently convert to/from internal representation +// (once there will be real usage at Rust side). +// #[sbor( +// as_type = "i64", +// as_ref = "self.timestamp()", +// from_value = "Self(DateTime::from_timestamp(value, 0))" +// )] +type PeerTimestamp = i64; + +/// Peer address entry with all components +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct PeerAddress { + pub encoded_uri: Vec, + pub latest_connection_status: Option, + pub last_seen: Option, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub enum ConnectionStatus { + Connected, + Disconnected, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct NodeIdDTO { + pub key: components::NodeSecp256k1PublicKey, +} + +/// Address book entry +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct AddressBookEntryV1 { + pub node_id: NodeIdDTO, + pub banned_until: Option, + pub known_addresses: Vec, +} + +define_single_versioned! { + #[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] + pub VersionedAddressBookEntry(AddressBookEntryVersions) => AddressBookEntry = AddressBookEntryV1 +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct HighPriorityPeersV1(Vec); + +define_single_versioned! { + #[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] + pub VersionedHighPriorityPeers(HighPriorityPeersVersions) => HighPriorityPeers = HighPriorityPeersV1 +} diff --git a/core-rust/p2p/src/column_families.rs b/core-rust/p2p/src/column_families.rs new file mode 100644 index 0000000000..3c4b247b97 --- /dev/null +++ b/core-rust/p2p/src/column_families.rs @@ -0,0 +1,114 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::address_book_components::*; +use crate::components::NodeSecp256k1PublicKey; +use crate::migration::MigrationStatus; +use crate::safety_store_components::{SafetyState, VersionedSafetyState}; +use crate::typed_cf_api::RawPublicKeyDbCodec; +use node_common::store::typed_cf_api::{DefaultCf, SborDbCodec, UnitDbCodec, VersionedCf}; + +/// Address book and safety state store migration status. Filled once during the migration. +pub struct MigrationStatusCf; +impl DefaultCf for MigrationStatusCf { + type Key = (); + type Value = MigrationStatus; + + const DEFAULT_NAME: &'static str = "migration_status"; + type KeyCodec = UnitDbCodec; + type ValueCodec = SborDbCodec; +} + +/// Address book +pub struct AddressBookCf; +impl VersionedCf for AddressBookCf { + type Key = NodeSecp256k1PublicKey; + type Value = AddressBookEntry; + + const VERSIONED_NAME: &'static str = "address_book"; + type KeyCodec = RawPublicKeyDbCodec; + type VersionedValue = VersionedAddressBookEntry; +} + +/// Safety store +pub struct SafetyStoreCf; +impl VersionedCf for SafetyStoreCf { + type Key = (); + type Value = SafetyState; + + const VERSIONED_NAME: &'static str = "safety_store"; + type KeyCodec = UnitDbCodec; + type VersionedValue = VersionedSafetyState; +} + +/// High priority peers +pub struct HighPriorityPeersCf; +impl VersionedCf for HighPriorityPeersCf { + type Key = (); + type Value = HighPriorityPeers; + + const VERSIONED_NAME: &'static str = "high_priority_peers"; + type KeyCodec = UnitDbCodec; + type VersionedValue = VersionedHighPriorityPeers; +} diff --git a/core-rust/p2p/src/components.rs b/core-rust/p2p/src/components.rs new file mode 100644 index 0000000000..78c4908c87 --- /dev/null +++ b/core-rust/p2p/src/components.rs @@ -0,0 +1,36 @@ +use crate::engine_prelude::{ScryptoCategorize, ScryptoDecode, ScryptoEncode}; + +/// The ID of the node stored in the Address book (Secp256k1 public key) +#[derive( + Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode, PartialOrd, Ord, PartialEq, Eq, +)] +#[sbor(transparent)] +pub struct NodeSecp256k1PublicKey(pub [u8; NodeSecp256k1PublicKey::LENGTH]); + +impl NodeSecp256k1PublicKey { + pub const LENGTH: usize = 33; + + pub fn new(id: [u8; Self::LENGTH]) -> Self { + Self(id) + } + + pub fn as_bytes(&self) -> &[u8; Self::LENGTH] { + &self.0 + } +} + +/// The Secp256K1 signature +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct NodeSignature(pub [u8; NodeSignature::LENGTH]); + +impl NodeSignature { + pub const LENGTH: usize = 65; // v(1) + r(32) + s(32) + + pub fn new(signature: [u8; Self::LENGTH]) -> Self { + Self(signature) + } + + pub fn as_bytes(&self) -> &[u8; Self::LENGTH] { + &self.0 + } +} diff --git a/core-rust/p2p/src/lib.rs b/core-rust/p2p/src/lib.rs new file mode 100644 index 0000000000..40a63c031a --- /dev/null +++ b/core-rust/p2p/src/lib.rs @@ -0,0 +1,12 @@ +pub mod address_book_components; +pub mod column_families; +pub mod components; +pub mod migration; +pub mod rocks_db; +pub mod safety_store_components; +pub mod traits; +pub mod typed_cf_api; + +pub mod engine_prelude { + pub use radix_common::prelude::*; +} diff --git a/core-rust/p2p/src/migration.rs b/core-rust/p2p/src/migration.rs new file mode 100644 index 0000000000..67edbc1259 --- /dev/null +++ b/core-rust/p2p/src/migration.rs @@ -0,0 +1,72 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use sbor::Sbor; + +/// Status of the migration +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Sbor)] +pub enum MigrationStatus { + Completed, +} diff --git a/core-rust/p2p/src/rocks_db.rs b/core-rust/p2p/src/rocks_db.rs new file mode 100644 index 0000000000..11271eb031 --- /dev/null +++ b/core-rust/p2p/src/rocks_db.rs @@ -0,0 +1,245 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use std::path::PathBuf; + +use node_common::rocksdb::{ColumnFamilyDescriptor, Options, DB}; + +use crate::address_book_components::*; +use crate::column_families::*; +use crate::components::NodeSecp256k1PublicKey; +use crate::engine_prelude::*; +use crate::migration::MigrationStatus; +use crate::safety_store_components::SafetyState; +use crate::traits::node::{AddressBookStore, HighPriorityPeersStore, SafetyStateStore}; +use node_common::store::rocks_db::*; +use node_common::store::typed_cf_api::*; + +/// A listing of all column family names used by the Node. +/// +/// This is directly needed to initialize the column families within the DB, but is also a nice +/// place to link to all of them (please see the documentation of each CF to learn about its +/// business purpose and DB schema) and to put the important general notes regarding all of them +/// (see below). +/// +/// **Note on the key encoding used throughout all column families:** +/// We often rely on the RocksDB's unsurprising ability to efficiently list entries sorted +/// lexicographically by key. For this reason, our byte-level encoding of certain keys (e.g. +/// [`StateVersion`]) needs to reflect the business-level ordering of the represented concept (i.e. +/// since state versions grow, the "last" state version must have a lexicographically greatest key, +/// which means that we need to use a constant-length big-endian integer encoding). +/// +/// **Note on the name strings:** +/// The `NAME` constants defined by `*Cf` structs (and referenced below) are used as database column +/// family names. Any change would effectively mean a ledger wipe. For this reason, we choose to +/// define them manually (rather than using the `Into`, which is refactor-sensitive). + +const ALL_ADDRESS_BOOK_COLUMN_FAMILIES: [&str; 3] = [ + AddressBookCf::VERSIONED_NAME, + HighPriorityPeersCf::VERSIONED_NAME, + MigrationStatusCf::DEFAULT_NAME, +]; + +const ALL_SAFETY_STORE_COLUMN_FAMILIES: [&str; 2] = + [SafetyStoreCf::DEFAULT_NAME, MigrationStatusCf::DEFAULT_NAME]; + +pub type ActualAddressBookDatabase = AddressBookDatabase; +pub type ActualSafetyStoreDatabase = SafetyStoreDatabase; + +/// A RocksDB-backed persistence layer for address book. +pub struct AddressBookDatabase { + /// Underlying RocksDB instance. + rocks: R, +} + +/// A RocksDB-backed persistence layer for safety store. +pub struct SafetyStoreDatabase { + /// Underlying RocksDB instance. + rocks: R, +} + +fn new_rocks_db(root_path: PathBuf, column_families: &[&str]) -> DB { + let mut db_opts = Options::default(); + db_opts.create_if_missing(true); + db_opts.create_missing_column_families(true); + + let column_families: Vec = column_families + .iter() + .map(|cf| ColumnFamilyDescriptor::new(cf.to_string(), Options::default())) + .collect(); + + DB::open_cf_descriptors(&db_opts, root_path.as_path(), column_families).unwrap() +} + +fn open_rw_context(db: &R) -> TypedDbContext> { + TypedDbContext::new(db, BufferedWriteSupport::new(db)) +} + +impl ActualAddressBookDatabase { + pub fn new(root_path: PathBuf) -> ActualAddressBookDatabase { + AddressBookDatabase { + rocks: DirectRocks { + db: new_rocks_db(root_path, &ALL_ADDRESS_BOOK_COLUMN_FAMILIES), + }, + } + } +} + +impl ActualSafetyStoreDatabase { + pub fn new(root_path: PathBuf) -> ActualSafetyStoreDatabase { + ActualSafetyStoreDatabase { + rocks: DirectRocks { + db: new_rocks_db(root_path, &ALL_SAFETY_STORE_COLUMN_FAMILIES), + }, + } + } +} + +impl AddressBookStore for AddressBookDatabase { + fn remove_one(&self, node_id: &NodeSecp256k1PublicKey) -> bool { + let binding = open_rw_context(&self.rocks); + let context = binding.cf(AddressBookCf); + + if context.get(node_id).is_some() { + context.delete(node_id); + } + + true + } + + fn upsert_one(&self, node_id: &NodeSecp256k1PublicKey, entry: &AddressBookEntry) -> bool { + let binding = open_rw_context(&self.rocks); + let context = binding.cf(AddressBookCf); + + context.put(node_id, &entry); + + true + } + + fn reset(&self) { + open_rw_context(&self.rocks).cf(AddressBookCf).delete_all(); + } + + fn get_all(&self) -> Vec { + open_rw_context(&self.rocks).cf(AddressBookCf).get_all() + } + + fn is_migrated(&self) -> bool { + open_rw_context(&self.rocks) + .cf(MigrationStatusCf) + .get(&()) + .is_some() + } + + fn mark_as_migrated(&self) { + open_rw_context(&self.rocks) + .cf(MigrationStatusCf) + .put(&(), &MigrationStatus::Completed) + } +} + +impl HighPriorityPeersStore for AddressBookDatabase { + fn upsert_all_high_priority_peers(&self, peers: &HighPriorityPeers) { + open_rw_context(&self.rocks) + .cf(HighPriorityPeersCf) + .put(&(), &peers); + } + + fn get_all_high_priority_peers(&self) -> Option { + open_rw_context(&self.rocks) + .cf(HighPriorityPeersCf) + .get(&()) + } + + fn reset_high_priority_peers(&self) { + open_rw_context(&self.rocks) + .cf(HighPriorityPeersCf) + .delete(&()); + } +} + +impl SafetyStateStore for SafetyStoreDatabase { + fn upsert_safety_state(&self, safety_state: &SafetyState) { + open_rw_context(&self.rocks) + .cf(SafetyStoreCf) + .put(&(), safety_state); + } + + fn get_safety_state(&self) -> Option { + open_rw_context(&self.rocks).cf(SafetyStoreCf).get(&()) + } + + fn is_migrated(&self) -> bool { + open_rw_context(&self.rocks) + .cf(MigrationStatusCf) + .get(&()) + .is_some() + } + + fn mark_as_migrated(&self) { + open_rw_context(&self.rocks) + .cf(MigrationStatusCf) + .put(&(), &MigrationStatus::Completed) + } +} diff --git a/core-rust/p2p/src/safety_store_components.rs b/core-rust/p2p/src/safety_store_components.rs new file mode 100644 index 0000000000..cabb80254c --- /dev/null +++ b/core-rust/p2p/src/safety_store_components.rs @@ -0,0 +1,206 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::components::{NodeSecp256k1PublicKey, NodeSignature}; +use crate::engine_prelude::*; +use sbor::define_single_versioned; + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct SafetyStateV1 { + validator_id: BFTValidatorId, + round: Round, + last_vote: Option, +} + +define_single_versioned! { + #[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] + pub VersionedSafetyState(SafetyStateVersions) => SafetyState = SafetyStateV1 +} + +/// Safety state components. Note that these structs are intended only for proper encoding/deconding +/// of the safety state. They may repeat existing structs defined elsewhere. + +/// Timestamp of the various safety state components. +// At present it's just an alias for i64. Later we may want to replace it with struct using crono crate and +// do something like shown below to transparently convert to/from internal representation +// (once there will be real usage at Rust side). +// #[sbor( +// as_type = "i64", +// as_ref = "self.timestamp()", +// from_value = "Self(DateTime::from_timestamp(value, 0))" +// )] +type SafetyStateTimestamp = i64; + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct BFTHeader { + round: Round, + vertex_id: VertexId, + ledger_header: LedgerHeader, +} + +#[derive( + Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode, Ord, PartialOrd, Eq, PartialEq, +)] +pub struct BFTValidator { + power: Vec, + validator_id: BFTValidatorId, +} + +#[derive( + Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode, Ord, PartialOrd, Eq, PartialEq, +)] +pub struct BFTValidatorId { + key: NodeSecp256k1PublicKey, + validator_address: ComponentAddress, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct HighQC { + highest_quorum_certificate: QuorumCertificate, + highest_committed_quorum_certificate: QuorumCertificate, + highest_timeout_certificate: Option, +} + +// FIXME: A duplicate of LedgerHeader from StateManager. +// Made separate te reference only types within this module. De-duplication requires +// careful merging of the other referenced types as well. +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct LedgerHeader { + epoch: i64, + round: Round, + state_version: i64, + hashes: LedgerHashes, + consensus_parent_round_timestamp_ms: SafetyStateTimestamp, + proposer_timestamp_ms: SafetyStateTimestamp, + next_epoch: Option, + next_protocol_version: Option, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct LedgerHashes { + pub state_root: RawHash, + pub transaction_root: RawHash, + pub receipt_root: RawHash, +} + +define_wrapped_hash! { + RawHash +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct NextEpoch { + epoch: i64, + validators: Vec, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct QuorumCertificate { + signatures: TimestampedECDSASignatures, + vote_data: VoteData, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct Round { + round: i64, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct TimeoutCertificate { + epoch: i64, + round: Round, + signatures: TimestampedECDSASignatures, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct TimestampedECDSASignature { + timestamp: SafetyStateTimestamp, + signature: NodeSignature, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct TimestampedECDSASignatures { + node_to_timestamped_signature: BTreeMap, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct VertexId { + id_bytes: Vec, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct Vote { + author: BFTValidatorId, + high_quorum_certificate: HighQC, + vote_data: VoteData, + timestamp: SafetyStateTimestamp, + signature: NodeSignature, + timeout_signature: Option, +} + +#[derive(Debug, Clone, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +pub struct VoteData { + proposed: BFTHeader, + parent: BFTHeader, + committed: Option, +} diff --git a/core-rust/p2p/src/traits.rs b/core-rust/p2p/src/traits.rs new file mode 100644 index 0000000000..ac1136d973 --- /dev/null +++ b/core-rust/p2p/src/traits.rs @@ -0,0 +1,95 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::engine_prelude::*; + +pub mod node { + use super::*; + use crate::address_book_components::*; + use crate::components::NodeSecp256k1PublicKey; + use crate::safety_store_components::SafetyState; + + pub trait AddressBookStore { + fn remove_one(&self, node_id: &NodeSecp256k1PublicKey) -> bool; + fn upsert_one(&self, node_id: &NodeSecp256k1PublicKey, entry: &AddressBookEntry) -> bool; + fn reset(&self); + fn get_all(&self) -> Vec; + fn is_migrated(&self) -> bool; + fn mark_as_migrated(&self); + } + + // At Java side it is represented as part of AddressBookStore + pub trait HighPriorityPeersStore { + fn upsert_all_high_priority_peers(&self, peers: &HighPriorityPeers); + fn get_all_high_priority_peers(&self) -> Option; + fn reset_high_priority_peers(&self); + } + + pub trait SafetyStateStore { + fn upsert_safety_state(&self, safety_state: &SafetyState); + fn get_safety_state(&self) -> Option; + fn is_migrated(&self) -> bool; + fn mark_as_migrated(&self); + } +} diff --git a/core-rust/p2p/src/typed_cf_api.rs b/core-rust/p2p/src/typed_cf_api.rs new file mode 100644 index 0000000000..9bf833e20c --- /dev/null +++ b/core-rust/p2p/src/typed_cf_api.rs @@ -0,0 +1,85 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::components::NodeSecp256k1PublicKey; +use node_common::store::typed_cf_api::{BoundedDbCodec, DbCodec}; + +#[derive(Clone, Default)] +pub struct RawPublicKeyDbCodec {} + +impl DbCodec for RawPublicKeyDbCodec { + fn encode(&self, value: &NodeSecp256k1PublicKey) -> Vec { + value.as_bytes().to_vec() + } + + fn decode(&self, bytes: &[u8]) -> NodeSecp256k1PublicKey { + NodeSecp256k1PublicKey::new(bytes.try_into().expect("Invalid NodeId")) + } +} + +impl BoundedDbCodec for RawPublicKeyDbCodec { + fn upper_bound_encoding(&self) -> Vec { + vec![0xFF; NodeSecp256k1PublicKey::LENGTH] + } +} diff --git a/core-rust/state-manager/Cargo.toml b/core-rust/state-manager/Cargo.toml index e6964692cf..304891533f 100644 --- a/core-rust/state-manager/Cargo.toml +++ b/core-rust/state-manager/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] node-common = { path = "../node-common" } +# Eventually this should be removed, but we need to move JNINodeRustEnvironment to other place firts. +p2p = { path = "../p2p" } sbor = { workspace = true } radix-transactions = { workspace = true } @@ -27,7 +29,6 @@ blake2 = { workspace = true } hex = { workspace = true } rand = { workspace = true } -rocksdb = { version = "=0.21.0" } lru = { version = "=0.8.1", default-features = false } slotmap = { version = "=1.0.6" } im = { version = "=15.1.0" } diff --git a/core-rust/state-manager/src/committer.rs b/core-rust/state-manager/src/committer.rs index 05da224c31..3b5890533f 100644 --- a/core-rust/state-manager/src/committer.rs +++ b/core-rust/state-manager/src/committer.rs @@ -80,7 +80,7 @@ use crate::system_commits::*; use crate::accumulator_tree::storage::ReadableAccuTreeStore; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use std::ops::Deref; use std::sync::Arc; use std::time::SystemTime; diff --git a/core-rust/state-manager/src/jni/mod.rs b/core-rust/state-manager/src/jni/mod.rs index 8a2af6ec09..ccb138dfd9 100644 --- a/core-rust/state-manager/src/jni/mod.rs +++ b/core-rust/state-manager/src/jni/mod.rs @@ -66,6 +66,7 @@ pub mod db_checkpoints; pub mod fatal_panic_handler; pub mod mempool; pub mod node_rust_environment; +pub mod p2p; pub mod prometheus; pub mod protocol_update; pub mod state_computer; diff --git a/core-rust/state-manager/src/jni/node_rust_environment.rs b/core-rust/state-manager/src/jni/node_rust_environment.rs index d91170b0d1..fb52268a51 100644 --- a/core-rust/state-manager/src/jni/node_rust_environment.rs +++ b/core-rust/state-manager/src/jni/node_rust_environment.rs @@ -61,8 +61,8 @@ * Work. You assume all risks associated with Your use of the Work and the exercise of * permissions under this License. */ - use std::ops::Deref; +use std::path::{PathBuf, MAIN_SEPARATOR}; use std::str::FromStr; use std::sync::Arc; @@ -86,10 +86,11 @@ use crate::priority_mempool::PriorityMempool; use super::fatal_panic_handler::FatalPanicHandler; use crate::protocol::ProtocolManager; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::transaction::Preparator; -use crate::{Committer, LedgerMetrics, SystemExecutor}; +use crate::{Committer, DatabaseBackendConfig, LedgerMetrics, SystemExecutor}; use crate::{StateManager, StateManagerConfig}; +use p2p::rocks_db::{ActualAddressBookDatabase, ActualSafetyStoreDatabase}; const POINTER_JNI_FIELD_NAME: &str = "rustNodeRustEnvironmentPointer"; @@ -122,15 +123,15 @@ pub struct JNINodeRustEnvironment { pub state_manager: StateManager, pub metric_registry: Arc, pub running_task_tracker: UntilDropTracker, + pub address_book_store: Arc, + pub safety_store_store: Arc, } impl JNINodeRustEnvironment { pub fn init(env: &JNIEnv, j_node_rust_env: JObject, j_config: jbyteArray) { - let config_bytes: Vec = jni_jbytearray_to_vector(env, j_config).unwrap(); - let config = StateManagerConfig::valid_from_java(&config_bytes).unwrap(); - + let (base_path, config) = + Self::prepare_config(&jni_jbytearray_to_vector(env, j_config).unwrap()); let network = config.network_definition.clone(); - let runtime = Arc::new(Runtime::new().unwrap()); setup_tracing( @@ -163,18 +164,44 @@ impl JNINodeRustEnvironment { let running_task_tracker = scheduler.into_task_tracker(); + let address_book_db_path = Self::combine(&base_path, "address_book"); + let safety_store_db_path = Self::combine(&base_path, "consensus_safety_store"); let jni_node_rust_env = JNINodeRustEnvironment { runtime, network, state_manager, metric_registry, running_task_tracker, + address_book_store: Arc::new(ActualAddressBookDatabase::new(address_book_db_path)), + safety_store_store: Arc::new(ActualSafetyStoreDatabase::new(safety_store_db_path)), }; env.set_rust_field(j_node_rust_env, POINTER_JNI_FIELD_NAME, jni_node_rust_env) .unwrap(); } + fn prepare_config(config_bytes: &[u8]) -> (String, StateManagerConfig) { + let config = StateManagerConfig::valid_from_java(config_bytes).unwrap(); + let base_path = config.database_backend_config.rocks_db_path.clone(); + let mut state_manager_db_path = config.database_backend_config.rocks_db_path.clone(); + + state_manager_db_path.push(MAIN_SEPARATOR); + state_manager_db_path.push_str("state_manager"); + + let config = StateManagerConfig { + database_backend_config: DatabaseBackendConfig { + rocks_db_path: state_manager_db_path, + }, + ..config + }; + + (base_path, config) + } + + fn combine(base: &String, ext: &str) -> PathBuf { + [base, ext].iter().collect() + } + pub fn cleanup(env: &JNIEnv, j_node_rust_env: JObject) { let jni_node_rust_env: JNINodeRustEnvironment = env .take_rust_field(j_node_rust_env, POINTER_JNI_FIELD_NAME) @@ -208,6 +235,20 @@ impl JNINodeRustEnvironment { .clone() } + pub fn get_address_book_database( + env: &JNIEnv, + j_node_rust_env: JObject, + ) -> Arc { + Self::get(env, j_node_rust_env).address_book_store.clone() + } + + pub fn get_safety_store_database( + env: &JNIEnv, + j_node_rust_env: JObject, + ) -> Arc { + Self::get(env, j_node_rust_env).safety_store_store.clone() + } + pub fn get_mempool(env: &JNIEnv, j_node_rust_env: JObject) -> Arc> { Self::get(env, j_node_rust_env) .state_manager diff --git a/core-rust/state-manager/src/jni/p2p/address_book.rs b/core-rust/state-manager/src/jni/p2p/address_book.rs new file mode 100644 index 0000000000..99ac69cbb4 --- /dev/null +++ b/core-rust/state-manager/src/jni/p2p/address_book.rs @@ -0,0 +1,149 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::engine_prelude::*; +use crate::jni::node_rust_environment::JNINodeRustEnvironment; +use jni::objects::{JClass, JObject}; +use jni::sys::jbyteArray; +use jni::JNIEnv; +use node_common::java::*; +use p2p::address_book_components::{AddressBookEntry, NodeIdDTO}; +use p2p::traits::node::AddressBookStore; + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbAddressBookStore_removeOne( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |request: NodeIdDTO| -> bool { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context) + .remove_one(&request.key) + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbAddressBookStore_upsertOne( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + address_entry: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, address_entry, |request: AddressBookEntry| -> bool { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context) + .upsert_one(&request.node_id.key, &request) + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbAddressBookStore_reset( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context).reset(); + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbAddressBookStore_getAll( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| -> Vec { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context).get_all() + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbAddressBookStore_markAsMigrated( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context) + .mark_as_migrated(); + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbAddressBookStore_isMigrated( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| -> bool { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context).is_migrated() + }) +} + +pub fn export_extern_functions() {} diff --git a/core-rust/state-manager/src/jni/p2p/high_priority_peers.rs b/core-rust/state-manager/src/jni/p2p/high_priority_peers.rs new file mode 100644 index 0000000000..f97eada408 --- /dev/null +++ b/core-rust/state-manager/src/jni/p2p/high_priority_peers.rs @@ -0,0 +1,114 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use jni::objects::{JClass, JObject}; +use jni::sys::jbyteArray; +use jni::JNIEnv; + +use crate::engine_prelude::*; +use crate::jni::node_rust_environment::JNINodeRustEnvironment; +use node_common::java::*; +use p2p::address_book_components::HighPriorityPeers; +use p2p::traits::node::HighPriorityPeersStore; + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbHighPriorityPeersStore_upsertAllHighPriorityPeers( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + payload: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, payload, |bytes| { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context) + .upsert_all_high_priority_peers(&bytes) + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbHighPriorityPeersStore_getAllHighPriorityPeers( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + payload: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, payload, |_: ()| -> Option { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context) + .get_all_high_priority_peers() + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_p2p_RocksDbHighPriorityPeersStore_resetHighPriorityPeers( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| { + JNINodeRustEnvironment::get_address_book_database(&env, j_rust_global_context) + .reset_high_priority_peers(); + }) +} + +pub fn export_extern_functions() {} diff --git a/core-rust/state-manager/src/jni/p2p/mod.rs b/core-rust/state-manager/src/jni/p2p/mod.rs new file mode 100644 index 0000000000..e210684976 --- /dev/null +++ b/core-rust/state-manager/src/jni/p2p/mod.rs @@ -0,0 +1,5 @@ +// This module should be eventually moved to p2p crate. + +pub mod address_book; +pub mod high_priority_peers; +pub mod safety_store; diff --git a/core-rust/state-manager/src/jni/p2p/safety_store.rs b/core-rust/state-manager/src/jni/p2p/safety_store.rs new file mode 100644 index 0000000000..da1e375192 --- /dev/null +++ b/core-rust/state-manager/src/jni/p2p/safety_store.rs @@ -0,0 +1,125 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +use crate::engine_prelude::*; +use crate::jni::node_rust_environment::JNINodeRustEnvironment; +use jni::objects::{JClass, JObject}; +use jni::sys::jbyteArray; +use jni::JNIEnv; +use node_common::java::*; +use p2p::safety_store_components::SafetyState; +use p2p::traits::node::SafetyStateStore; + +#[no_mangle] +extern "system" fn Java_com_radixdlt_safety_RocksDbSafetyStore_upsert( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + request: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, request, |safety_state| { + JNINodeRustEnvironment::get_safety_store_database(&env, j_rust_global_context) + .upsert_safety_state(&safety_state) + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_safety_RocksDbSafetyStore_get( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| -> Option { + JNINodeRustEnvironment::get_safety_store_database(&env, j_rust_global_context) + .get_safety_state() + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_safety_RocksDbSafetyStore_markAsMigrated( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| { + JNINodeRustEnvironment::get_safety_store_database(&env, j_rust_global_context) + .mark_as_migrated(); + }) +} + +#[no_mangle] +extern "system" fn Java_com_radixdlt_safety_RocksDbSafetyStore_isMigrated( + env: JNIEnv, + _class: JClass, + j_rust_global_context: JObject, + node_id: jbyteArray, +) -> jbyteArray { + jni_sbor_coded_call(&env, node_id, |_: ()| -> bool { + JNINodeRustEnvironment::get_safety_store_database(&env, j_rust_global_context).is_migrated() + }) +} + +pub fn export_extern_functions() {} diff --git a/core-rust/state-manager/src/jni/test_state_reader.rs b/core-rust/state-manager/src/jni/test_state_reader.rs index 2b2ccc6397..225e434eb4 100644 --- a/core-rust/state-manager/src/jni/test_state_reader.rs +++ b/core-rust/state-manager/src/jni/test_state_reader.rs @@ -73,11 +73,11 @@ use crate::jni::node_rust_environment::JNINodeRustEnvironment; use crate::query::StateManagerSubstateQueries; use node_common::java::*; +use crate::store::traits::measurement::MeasurableDatabase; use crate::store::traits::{ gc::StateTreeGcStore, IterableProofStore, QueryableProofStore, QueryableTransactionStore, SubstateNodeAncestryStore, }; -use crate::traits::measurement::MeasurableDatabase; use crate::transaction::LedgerTransactionHash; // diff --git a/core-rust/state-manager/src/metrics.rs b/core-rust/state-manager/src/metrics.rs index 2267225801..f1cdbc5e35 100644 --- a/core-rust/state-manager/src/metrics.rs +++ b/core-rust/state-manager/src/metrics.rs @@ -81,7 +81,7 @@ use crate::protocol::{ PendingProtocolUpdateState, ProtocolState, ProtocolUpdateEnactmentCondition, }; use crate::store::traits::measurement::CategoryDbVolumeStatistic; -use crate::traits::QueryableProofStore; +use crate::store::traits::QueryableProofStore; pub struct LedgerMetrics { address_encoder: AddressBech32Encoder, // for label rendering only diff --git a/core-rust/state-manager/src/protocol/protocol_state.rs b/core-rust/state-manager/src/protocol/protocol_state.rs index 0471c3a9a3..978e44728e 100644 --- a/core-rust/state-manager/src/protocol/protocol_state.rs +++ b/core-rust/state-manager/src/protocol/protocol_state.rs @@ -8,9 +8,9 @@ use std::sync::Arc; use tracing::info; use crate::protocol::*; -use crate::traits::{IterableProofStore, QueryableProofStore, QueryableTransactionStore}; +use crate::store::traits::{IterableProofStore, QueryableProofStore, QueryableTransactionStore}; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::{ LocalTransactionReceipt, ProtocolMetrics, ScenariosExecutionConfig, StateVersion, SystemExecutor, diff --git a/core-rust/state-manager/src/protocol/protocol_updates/definitions/anemone_definition.rs b/core-rust/state-manager/src/protocol/protocol_updates/definitions/anemone_definition.rs index 38d63864b0..9b36eb988b 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/definitions/anemone_definition.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/anemone_definition.rs @@ -1,6 +1,6 @@ use crate::engine_prelude::*; use crate::protocol::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use node_common::locks::DbLock; use std::sync::Arc; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/definitions/bottlenose_definition.rs b/core-rust/state-manager/src/protocol/protocol_updates/definitions/bottlenose_definition.rs index a5dbeabeae..48530042a7 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/definitions/bottlenose_definition.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/bottlenose_definition.rs @@ -1,6 +1,6 @@ use crate::engine_prelude::*; use crate::protocol::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use node_common::locks::DbLock; use std::sync::Arc; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/definitions/custom_definition.rs b/core-rust/state-manager/src/protocol/protocol_updates/definitions/custom_definition.rs index 2ae872c30c..8a7fbff9d9 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/definitions/custom_definition.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/custom_definition.rs @@ -1,6 +1,6 @@ use crate::engine_prelude::*; use crate::protocol::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use node_common::locks::DbLock; use std::sync::Arc; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/definitions/default_definition.rs b/core-rust/state-manager/src/protocol/protocol_updates/definitions/default_definition.rs index 46211cc4f1..8491f2fe7e 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/definitions/default_definition.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/default_definition.rs @@ -1,6 +1,6 @@ use crate::engine_prelude::*; use crate::protocol::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use node_common::locks::DbLock; use std::sync::Arc; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/definitions/mod.rs b/core-rust/state-manager/src/protocol/protocol_updates/definitions/mod.rs index 1dc9660b9b..8913985b9f 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/definitions/mod.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/mod.rs @@ -12,7 +12,7 @@ pub use test_definition::*; use crate::engine_prelude::*; use crate::protocol::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::transaction::*; use node_common::locks::DbLock; use std::ops::Deref; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/definitions/test_definition.rs b/core-rust/state-manager/src/protocol/protocol_updates/definitions/test_definition.rs index aec38fa174..c7e9c2432b 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/definitions/test_definition.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/test_definition.rs @@ -1,5 +1,5 @@ use crate::engine_prelude::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::{protocol::*, transaction::FlashTransactionV1}; use node_common::locks::DbLock; use std::sync::Arc; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_definition.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_definition.rs index 2f9795c40c..5e14d7bbb5 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_definition.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_definition.rs @@ -2,7 +2,7 @@ use crate::engine_prelude::*; use crate::protocol::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use node_common::locks::DbLock; use std::sync::Arc; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_progress.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_progress.rs index 23e46db125..a9c9f1f8c4 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_progress.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_progress.rs @@ -2,7 +2,7 @@ use crate::engine_prelude::*; use crate::protocol::*; -use crate::traits::*; +use crate::store::traits::*; use crate::LedgerProofOrigin; diff --git a/core-rust/state-manager/src/protocol/test.rs b/core-rust/state-manager/src/protocol/test.rs index cf280eb22a..a7a9f8561d 100644 --- a/core-rust/state-manager/src/protocol/test.rs +++ b/core-rust/state-manager/src/protocol/test.rs @@ -63,7 +63,7 @@ */ use crate::engine_prelude::*; -use crate::traits::QueryableProofStore; +use crate::store::traits::QueryableProofStore; use crate::protocol::*; use crate::{LedgerProof, LedgerProofOrigin, StateManagerConfig}; diff --git a/core-rust/state-manager/src/staging/cache.rs b/core-rust/state-manager/src/staging/cache.rs index 9f083682e5..64b818973c 100644 --- a/core-rust/state-manager/src/staging/cache.rs +++ b/core-rust/state-manager/src/staging/cache.rs @@ -86,9 +86,9 @@ use crate::{ use im::hashmap::HashMap as ImmutableHashMap; use itertools::Itertools; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; +use crate::store::traits::{ConfigurableDatabase, QueryableProofStore}; use crate::store::traits::{SubstateNodeAncestryRecord, SubstateNodeAncestryStore}; -use crate::traits::{ConfigurableDatabase, QueryableProofStore}; use node_common::locks::{DbLock, LockFactory, Mutex}; use slotmap::SecondaryMap; diff --git a/core-rust/state-manager/src/staging/mod.rs b/core-rust/state-manager/src/staging/mod.rs index 6c182d2c78..02f7a180b5 100644 --- a/core-rust/state-manager/src/staging/mod.rs +++ b/core-rust/state-manager/src/staging/mod.rs @@ -73,8 +73,8 @@ use crate::accumulator_tree::storage::ReadableAccuTreeStore; use crate::engine_prelude::*; use crate::{ReceiptTreeHash, StateVersion, TransactionTreeHash}; +use crate::store::traits::ConfigurableDatabase; use crate::store::traits::SubstateNodeAncestryStore; -use crate::traits::ConfigurableDatabase; pub use cache::*; pub use result::*; diff --git a/core-rust/state-manager/src/staging/result.rs b/core-rust/state-manager/src/staging/result.rs index b134367d87..143dc21111 100644 --- a/core-rust/state-manager/src/staging/result.rs +++ b/core-rust/state-manager/src/staging/result.rs @@ -79,8 +79,8 @@ use crate::staging::ReadableStore; use crate::staging::node_ancestry_resolver::NodeAncestryResolver; use crate::staging::overlays::{MapSubstateNodeAncestryStore, StagedSubstateNodeAncestryStore}; +use crate::store::traits::{ConfigurableDatabase, LeafSubstateKeyAssociation}; use crate::store::traits::{KeyedSubstateNodeAncestryRecord, SubstateNodeAncestryStore}; -use crate::traits::{ConfigurableDatabase, LeafSubstateKeyAssociation}; use node_common::utils::IsAccountExt; pub enum ProcessedTransactionReceipt { diff --git a/core-rust/state-manager/src/state_manager.rs b/core-rust/state-manager/src/state_manager.rs index a9dc368932..a7ad97b8cd 100644 --- a/core-rust/state-manager/src/state_manager.rs +++ b/core-rust/state-manager/src/state_manager.rs @@ -72,11 +72,11 @@ use crate::jni::LedgerSyncLimitsConfig; use crate::protocol::{ ProtocolConfig, ProtocolManager, ProtocolUpdateExecutor, ProtocolVersionName, }; -use crate::rocks_db::{ActualStateManagerDatabase, StateManagerDatabase}; use crate::store::jmt_gc::StateTreeGcConfig; use crate::store::proofs_gc::{LedgerProofsGc, LedgerProofsGcConfig}; +use crate::store::rocks_db::{ActualStateManagerDatabase, StateManagerDatabase}; use crate::store::traits::proofs::QueryableProofStore; -use crate::traits::DatabaseConfigValidationError; +use crate::store::traits::DatabaseConfigValidationError; use crate::transaction::{ ExecutionConfigurator, LedgerTransactionValidator, Preparator, TransactionExecutorFactory, }; diff --git a/core-rust/state-manager/src/store/codecs.rs b/core-rust/state-manager/src/store/codecs.rs index 73ae02b7b8..c87c2e6aa5 100644 --- a/core-rust/state-manager/src/store/codecs.rs +++ b/core-rust/state-manager/src/store/codecs.rs @@ -69,9 +69,9 @@ use crate::engine_prelude::*; use crate::store::traits::indices::CreationId; use crate::store::traits::scenario::ScenarioSequenceNumber; -use crate::store::typed_cf_api::*; use crate::transaction::RawLedgerTransaction; use crate::StateVersion; +use node_common::store::typed_cf_api::*; #[derive(Default)] pub struct StateVersionDbCodec {} @@ -260,7 +260,7 @@ impl DbCodec for StoredTreeNodeKeyDbCodec { impl BoundedDbCodec for StoredTreeNodeKeyDbCodec { fn upper_bound_encoding(&self) -> Vec { // Note: here we use knowledge of `encode_key()`'s internals: it puts the state version - // first. Additionally we need to assume that maximum state version is never reached. + // first. Additionally, we need to assume that maximum state version is never reached. encode_key(&StoredTreeNodeKey::new( Version::MAX, NibblePath::new_even(vec![]), diff --git a/core-rust/state-manager/src/store/column_families.rs b/core-rust/state-manager/src/store/column_families.rs new file mode 100644 index 0000000000..6a5756bb0c --- /dev/null +++ b/core-rust/state-manager/src/store/column_families.rs @@ -0,0 +1,405 @@ +use std::fmt; + +use radix_common::crypto::Hash; +use radix_common::prelude::{EntityType, Epoch, GlobalAddress, NodeId, PackageAddress}; +use radix_substate_store_impls::state_tree::tree_store::*; +use radix_substate_store_interface::interface::{DbSubstateKey, DbSubstateValue}; +use radix_transactions::model::{IntentHash, NotarizedTransactionHash}; + +use crate::store::codecs::*; +use crate::store::traits::gc::{LedgerProofsGcProgress, VersionedLedgerProofsGcProgress}; +use crate::store::traits::indices::*; +use crate::store::traits::scenario::*; +use crate::store::traits::*; +use crate::transaction::{LedgerTransactionHash, RawLedgerTransaction}; +use crate::*; +use node_common::store::typed_cf_api::*; + +/// Committed transactions. +/// Schema: `StateVersion.to_bytes()` -> `RawLedgerTransaction.as_ref::<[u8]>()` +/// Note: This table does not use explicit versioning wrapper, since the serialized content of +/// [`RawLedgerTransaction`] is itself versioned. +pub struct RawLedgerTransactionsCf; +impl DefaultCf for RawLedgerTransactionsCf { + type Key = StateVersion; + type Value = RawLedgerTransaction; + + const DEFAULT_NAME: &'static str = "raw_ledger_transactions"; + type KeyCodec = StateVersionDbCodec; + type ValueCodec = RawLedgerTransactionDbCodec; +} + +/// Identifiers of committed transactions. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedCommittedTransactionIdentifiers)` +pub struct CommittedTransactionIdentifiersCf; +impl VersionedCf for CommittedTransactionIdentifiersCf { + type Key = StateVersion; + type Value = CommittedTransactionIdentifiers; + + const VERSIONED_NAME: &'static str = "committed_transaction_identifiers"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedCommittedTransactionIdentifiers; +} + +/// Ledger receipts of committed transactions. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerTransactionReceipt)` +pub struct TransactionReceiptsCf; +impl VersionedCf for TransactionReceiptsCf { + type Key = StateVersion; + type Value = LedgerTransactionReceipt; + + const VERSIONED_NAME: &'static str = "transaction_receipts"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedLedgerTransactionReceipt; +} + +/// Off-ledger details of committed transaction results (stored only when configured via +/// `enable_local_transaction_execution_index`). +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLocalTransactionExecution)` +pub struct LocalTransactionExecutionsCf; +impl VersionedCf for LocalTransactionExecutionsCf { + type Key = StateVersion; + type Value = LocalTransactionExecution; + + const VERSIONED_NAME: &'static str = "local_transaction_executions"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedLocalTransactionExecution; +} + +/// Ledger proofs of committed transactions. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` +pub struct LedgerProofsCf; +impl VersionedCf for LedgerProofsCf { + type Key = StateVersion; + type Value = LedgerProof; + + const VERSIONED_NAME: &'static str = "ledger_proofs"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedLedgerProof; +} + +/// Ledger proofs of new epochs - i.e. the proofs which trigger the given `next_epoch`. +/// Schema: `Epoch.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` +/// Note: This duplicates a small subset of [`LedgerProofsCf`]'s values. +pub struct EpochLedgerProofsCf; +impl VersionedCf for EpochLedgerProofsCf { + type Key = Epoch; + type Value = LedgerProof; + + const VERSIONED_NAME: &'static str = "epoch_ledger_proofs"; + type KeyCodec = EpochDbCodec; + type VersionedValue = VersionedLedgerProof; +} + +/// Ledger proofs that initialize protocol updates, i.e. proofs of Consensus `origin`, +/// with headers containing a non-empty `next_protocol_version`. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` +/// Note: This duplicates a small subset of [`LedgerProofsCf`]'s values. +pub struct ProtocolUpdateInitLedgerProofsCf; +impl VersionedCf for ProtocolUpdateInitLedgerProofsCf { + type Key = StateVersion; + type Value = LedgerProof; + + const VERSIONED_NAME: &'static str = "protocol_update_init_ledger_proofs"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedLedgerProof; +} + +/// Ledger proofs of ProtocolUpdate `origin`, i.e. proofs created locally +/// while protocol update state modifications were being applied. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` +/// Note: This duplicates a small subset of [`LedgerProofsCf`]'s values. +pub struct ProtocolUpdateExecutionLedgerProofsCf; +impl VersionedCf for ProtocolUpdateExecutionLedgerProofsCf { + type Key = StateVersion; + type Value = LedgerProof; + + const VERSIONED_NAME: &'static str = "protocol_update_execution_ledger_proofs"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedLedgerProof; +} + +/// DB "index" table for transaction's [`IntentHash`] resolution. +/// Schema: `IntentHash.as_ref::<[u8]>()` -> `StateVersion.to_bytes()` +/// Note: This table does not use explicit versioning wrapper, since the value represents a DB +/// key of another table (and versioning DB keys is not useful). +pub struct IntentHashesCf; +impl DefaultCf for IntentHashesCf { + type Key = IntentHash; + type Value = StateVersion; + + const DEFAULT_NAME: &'static str = "intent_hashes"; + type KeyCodec = HashDbCodec; + type ValueCodec = StateVersionDbCodec; +} + +/// DB "index" table for transaction's [`NotarizedTransactionHash`] resolution. +/// Schema: `NotarizedTransactionHash.as_ref::<[u8]>()` -> `StateVersion.to_bytes()` +/// Note: This table does not use explicit versioning wrapper, since the value represents a DB +/// key of another table (and versioning DB keys is not useful). +pub struct NotarizedTransactionHashesCf; +impl DefaultCf for NotarizedTransactionHashesCf { + type Key = NotarizedTransactionHash; + type Value = StateVersion; + + const DEFAULT_NAME: &'static str = "notarized_transaction_hashes"; + type KeyCodec = HashDbCodec; + type ValueCodec = StateVersionDbCodec; +} + +/// DB "index" table for transaction's [`LedgerTransactionHash`] resolution. +/// Schema: `LedgerTransactionHash.as_ref::<[u8]>()` -> `StateVersion.to_bytes()` +/// Note: This table does not use explicit versioning wrapper, since the value represents a DB +/// key of another table (and versioning DB keys is not useful). +pub struct LedgerTransactionHashesCf; +impl DefaultCf for LedgerTransactionHashesCf { + type Key = LedgerTransactionHash; + type Value = StateVersion; + + const DEFAULT_NAME: &'static str = "ledger_transaction_hashes"; + type KeyCodec = HashDbCodec; + type ValueCodec = StateVersionDbCodec; +} + +/// Radix Engine's runtime Substate database. +/// Schema: `encode_to_rocksdb_bytes(DbPartitionKey, DbSortKey)` -> `Vec` +/// Note: This table does not use explicit versioning wrapper, since each serialized substate +/// value is already versioned. +pub struct SubstatesCf; +impl DefaultCf for SubstatesCf { + type Key = DbSubstateKey; + type Value = DbSubstateValue; + + const DEFAULT_NAME: &'static str = "substates"; + type KeyCodec = SubstateKeyDbCodec; + type ValueCodec = DirectDbCodec; +} + +/// Ancestor information for the RE Nodes of [`Substates`] (which is useful and can be computed, +/// but is not provided by the Engine itself). +/// Schema: `NodeId.0` -> `scrypto_encode(VersionedSubstateNodeAncestryRecord)` +/// Note: we do not persist records of root Nodes (which do not have any ancestor). +pub struct SubstateNodeAncestryRecordsCf; +impl VersionedCf for SubstateNodeAncestryRecordsCf { + type Key = NodeId; + type Value = SubstateNodeAncestryRecord; + + const VERSIONED_NAME: &'static str = "substate_node_ancestry_records"; + type KeyCodec = NodeIdDbCodec; + type VersionedValue = VersionedSubstateNodeAncestryRecord; +} + +/// Vertex store. +/// Schema: `[]` -> `scrypto_encode(VersionedVertexStoreBlob)` +/// Note: This is a single-entry table (i.e. the empty key is the only allowed key). +pub struct VertexStoreCf; +impl VersionedCf for VertexStoreCf { + type Key = (); + type Value = VertexStoreBlob; + + const VERSIONED_NAME: &'static str = "vertex_store"; + type KeyCodec = UnitDbCodec; + type VersionedValue = VersionedVertexStoreBlob; +} + +/// Individual nodes of the Substate database's hash tree. +/// Schema: `encode_key(StoredTreeNodeKey)` -> `scrypto_encode(VersionedTreeNode)`. +pub struct StateTreeNodesCf; +impl VersionedCf for StateTreeNodesCf { + type Key = StoredTreeNodeKey; + type Value = TreeNode; + + // Note: the legacy `state_hash_tree` name lives on here because it already got persisted. + const VERSIONED_NAME: &'static str = "state_hash_tree_nodes"; + type KeyCodec = StoredTreeNodeKeyDbCodec; + type VersionedValue = VersionedTreeNode; +} + +/// Parts of the Substate database's hash tree that became stale at a specific state version. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedStaleTreeParts)`. +pub struct StaleStateTreePartsCf; +impl VersionedCf for StaleStateTreePartsCf { + type Key = StateVersion; + type Value = StaleTreeParts; + + // Note: the legacy `state_hash_tree` name lives on here because it already got persisted. + const VERSIONED_NAME: &'static str = "stale_state_hash_tree_parts"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedStaleTreeParts; +} + +/// Transaction accumulator tree slices added at a specific state version. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedTransactionAccuTreeSlice)`. +pub struct TransactionAccuTreeSlicesCf; +impl VersionedCf for TransactionAccuTreeSlicesCf { + type Key = StateVersion; + type Value = TransactionAccuTreeSlice; + + const VERSIONED_NAME: &'static str = "transaction_accu_tree_slices"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedTransactionAccuTreeSlice; +} + +/// Receipt accumulator tree slices added at a specific state version. +/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedReceiptAccuTreeSlice)`. +pub struct ReceiptAccuTreeSlicesCf; +impl VersionedCf for ReceiptAccuTreeSlicesCf { + type Key = StateVersion; + type Value = ReceiptAccuTreeSlice; + + const VERSIONED_NAME: &'static str = "receipt_accu_tree_slices"; + type KeyCodec = StateVersionDbCodec; + type VersionedValue = VersionedReceiptAccuTreeSlice; +} + +/// An enum key for [`ExtensionsDataCf`]. +#[derive(Eq, PartialEq, Hash, PartialOrd, Ord, Clone, Debug)] +pub enum ExtensionsDataKey { + AccountChangeIndexLastProcessedStateVersion, + AccountChangeIndexEnabled, + LocalTransactionExecutionIndexEnabled, + December2023LostSubstatesRestored, + StateTreeAssociatedValuesStatus, + EntityListingIndicesLastProcessedStateVersion, +} + +// IMPORTANT NOTE: the strings defined below are used as database identifiers. Any change would +// effectively clear the associated extension's state in DB. For this reason, we choose to +// define them manually (rather than using the enum's `Into`, which is refactor-sensitive). +impl fmt::Display for ExtensionsDataKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = match self { + Self::AccountChangeIndexLastProcessedStateVersion => { + "account_change_index_last_processed_state_version" + } + Self::AccountChangeIndexEnabled => "account_change_index_enabled", + Self::LocalTransactionExecutionIndexEnabled => { + "local_transaction_execution_index_enabled" + } + Self::December2023LostSubstatesRestored => "december_2023_lost_substates_restored", + Self::StateTreeAssociatedValuesStatus => "state_tree_associated_values_status", + Self::EntityListingIndicesLastProcessedStateVersion => { + "entity_listing_indices_last_processed_state_version" + } + }; + write!(f, "{str}") + } +} + +/// Various data needed by extensions. +/// Schema: `ExtensionsDataKeys.to_string().as_bytes() -> Vec`. +/// Note: This table does not use explicit versioning wrapper, since each extension manages the +/// serialization of their data (of its custom type). +pub struct ExtensionsDataCf; +impl TypedCf for ExtensionsDataCf { + type Key = ExtensionsDataKey; + type Value = Vec; + + type KeyCodec = PredefinedDbCodec; + type ValueCodec = DirectDbCodec; + + const NAME: &'static str = "extensions_data"; + + fn key_codec(&self) -> PredefinedDbCodec { + PredefinedDbCodec::new_from_string_representations(vec![ + ExtensionsDataKey::AccountChangeIndexEnabled, + ExtensionsDataKey::AccountChangeIndexLastProcessedStateVersion, + ExtensionsDataKey::LocalTransactionExecutionIndexEnabled, + ExtensionsDataKey::December2023LostSubstatesRestored, + ExtensionsDataKey::StateTreeAssociatedValuesStatus, + ExtensionsDataKey::EntityListingIndicesLastProcessedStateVersion, + ]) + } + + fn value_codec(&self) -> DirectDbCodec { + DirectDbCodec::default() + } +} + +/// Account addresses and state versions at which they were changed. +/// Schema: `[GlobalAddress.0, StateVersion.to_bytes()].concat() -> []`. +/// Note: This is a key-only table (i.e. the empty value is the only allowed value). Given fast +/// prefix iterator from RocksDB this emulates a `Map>`. +pub struct AccountChangeStateVersionsCf; +impl TypedCf for AccountChangeStateVersionsCf { + type Key = (GlobalAddress, StateVersion); + type Value = (); + + type KeyCodec = PrefixGlobalAddressDbCodec; + type ValueCodec = UnitDbCodec; + + const NAME: &'static str = "account_change_state_versions"; + + fn key_codec(&self) -> PrefixGlobalAddressDbCodec { + PrefixGlobalAddressDbCodec::new(StateVersionDbCodec::default()) + } + + fn value_codec(&self) -> UnitDbCodec { + UnitDbCodec::default() + } +} + +/// Additional details of "Scenarios" (and their transactions) executed as part of Genesis, +/// keyed by their sequence number (i.e. their index in the list of Scenarios to execute). +/// Schema: `ScenarioSequenceNumber.to_be_bytes()` -> `scrypto_encode(VersionedExecutedScenario)` +pub struct ExecutedScenariosCf; +impl VersionedCf for ExecutedScenariosCf { + type Key = ScenarioSequenceNumber; + type Value = ExecutedScenario; + + // Note: a legacy name is still used here, even though we now have scenarios run outside Genesis + const VERSIONED_NAME: &'static str = "executed_genesis_scenarios"; + type KeyCodec = ScenarioSequenceNumberDbCodec; + type VersionedValue = VersionedExecutedScenario; +} + +/// Progress of the GC process pruning the [`LedgerProofsCf`]. +/// Schema: `[]` -> `scrypto_encode(VersionedLedgerProofsGcProgress)` +/// Note: This is a single-entry table (i.e. the empty key is the only allowed key). +pub struct LedgerProofsGcProgressCf; +impl VersionedCf for LedgerProofsGcProgressCf { + type Key = (); + type Value = LedgerProofsGcProgress; + + const VERSIONED_NAME: &'static str = "ledger_proofs_gc_progress"; + type KeyCodec = UnitDbCodec; + type VersionedValue = VersionedLedgerProofsGcProgress; +} + +/// Node IDs and blueprints of all entities, indexed by their type and creation order. +/// Schema: `[EntityType as u8, StateVersion.to_be_bytes(), (index_within_txn as u32).to_be_bytes()].concat()` -> `scrypto_encode(VersionedEntityBlueprintId)` +pub struct TypeAndCreationIndexedEntitiesCf; +impl VersionedCf for TypeAndCreationIndexedEntitiesCf { + type Key = (EntityType, CreationId); + type Value = EntityBlueprintId; + + const VERSIONED_NAME: &'static str = "type_and_creation_indexed_entities"; + type KeyCodec = TypeAndCreationIndexKeyDbCodec; + type VersionedValue = VersionedEntityBlueprintId; +} + +/// Node IDs and blueprints of all objects, indexed by their blueprint ID and creation order. +/// Schema: `[PackageAddress.0, hash(blueprint_name), StateVersion.to_be_bytes(), (index_within_txn as u32).to_be_bytes()].concat()` -> `scrypto_encode(VersionedObjectBlueprintName)` +pub struct BlueprintAndCreationIndexedObjectsCf; +impl VersionedCf for BlueprintAndCreationIndexedObjectsCf { + type Key = (PackageAddress, Hash, CreationId); + type Value = ObjectBlueprintName; + + const VERSIONED_NAME: &'static str = "blueprint_and_creation_indexed_objects"; + type KeyCodec = BlueprintAndCreationIndexKeyDbCodec; + type VersionedValue = VersionedObjectBlueprintName; +} + +/// Substate values associated with leaf nodes of the state hash tree's Substate Tier. +/// Needed for [`LeafSubstateValueStore`]. +/// Note: This table does not use explicit versioning wrapper, since each serialized substate +/// value is already versioned. +pub struct AssociatedStateTreeValuesCf; +impl DefaultCf for AssociatedStateTreeValuesCf { + type Key = StoredTreeNodeKey; + type Value = DbSubstateValue; + + const DEFAULT_NAME: &'static str = "associated_state_tree_values"; + type KeyCodec = StoredTreeNodeKeyDbCodec; + type ValueCodec = DirectDbCodec; +} diff --git a/core-rust/state-manager/src/store/historical_state.rs b/core-rust/state-manager/src/store/historical_state.rs index 977e162bcf..6a3accc1db 100644 --- a/core-rust/state-manager/src/store/historical_state.rs +++ b/core-rust/state-manager/src/store/historical_state.rs @@ -67,10 +67,11 @@ use std::ops::Deref; use crate::engine_prelude::entity_tier::EntityTier; use crate::engine_prelude::*; use crate::query::StateManagerSubstateQueries; -use crate::rocks_db::{ReadableRocks, StateManagerDatabase}; +use crate::store::rocks_db::StateManagerDatabase; +use crate::store::traits::indices::{CreationId, EntityBlueprintId, EntityListingIndex}; use crate::store::traits::*; -use crate::traits::indices::{CreationId, EntityBlueprintId, EntityListingIndex}; use crate::{CommittedTransactionIdentifiers, LedgerStateSummary, StateVersion}; +use node_common::store::rocks_db::ReadableRocks; /// An implementation of a [`SubstateDatabase`] viewed at a specific [`StateVersion`]. /// diff --git a/core-rust/state-manager/src/store/jmt_gc.rs b/core-rust/state-manager/src/store/jmt_gc.rs index 8c618f6023..a2ba3822d6 100644 --- a/core-rust/state-manager/src/store/jmt_gc.rs +++ b/core-rust/state-manager/src/store/jmt_gc.rs @@ -70,7 +70,7 @@ use std::sync::Arc; use std::time::Duration; use tracing::info; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::store::traits::gc::StateTreeGcStore; use crate::store::traits::proofs::QueryableProofStore; use crate::store::traits::StaleTreePartsV1; diff --git a/core-rust/state-manager/src/store/mod.rs b/core-rust/state-manager/src/store/mod.rs index c79bbcf5fd..5263dee145 100644 --- a/core-rust/state-manager/src/store/mod.rs +++ b/core-rust/state-manager/src/store/mod.rs @@ -62,22 +62,25 @@ * permissions under this License. */ +use std::sync::Arc; + +use prometheus::Registry; +use sbor::{Categorize, Decode, Encode}; + +use node_common::locks::DbLock; +use rocks_db::ActualStateManagerDatabase; + +use crate::RawDbMetrics; +use traits::measurement::MeasurableDatabase; +pub use traits::DatabaseConfig; + mod codecs; +pub mod column_families; pub mod historical_state; pub mod jmt_gc; pub mod proofs_gc; pub mod rocks_db; pub mod traits; -mod typed_cf_api; - -use crate::store::traits::measurement::MeasurableDatabase; -use crate::RawDbMetrics; -use node_common::locks::DbLock; -use prometheus::Registry; -use rocks_db::ActualStateManagerDatabase; -use sbor::{Categorize, Decode, Encode}; -use std::sync::Arc; -pub use traits::DatabaseConfig; #[derive(Debug, Categorize, Encode, Decode, Clone)] pub struct DatabaseBackendConfig { diff --git a/core-rust/state-manager/src/store/proofs_gc.rs b/core-rust/state-manager/src/store/proofs_gc.rs index 7e2d74e160..e08201d3e4 100644 --- a/core-rust/state-manager/src/store/proofs_gc.rs +++ b/core-rust/state-manager/src/store/proofs_gc.rs @@ -75,13 +75,13 @@ use crate::store::traits::gc::{ use crate::store::traits::proofs::QueryableProofStore; use crate::jni::LedgerSyncLimitsConfig; -use crate::rocks_db::{ActualStateManagerDatabase, StateManagerDatabase}; -use crate::store::rocks_db::ReadableRocks; -use crate::traits::GetSyncableTxnsAndProofError::{ +use crate::store::rocks_db::{ActualStateManagerDatabase, StateManagerDatabase}; +use crate::store::traits::GetSyncableTxnsAndProofError::{ FailedToPrepareAResponseWithinLimits, NothingToServeAtTheGivenStateVersion, RefusedToServeGenesis, RefusedToServeProtocolUpdate, }; use crate::{LedgerProof, StateVersion}; +use node_common::store::rocks_db::ReadableRocks; /// A configuration for [`LedgerProofsGc`]. #[derive(Debug, Categorize, Encode, Decode, Clone, Default)] @@ -313,8 +313,8 @@ mod tests { use crate::proofs_gc::{LedgerProofsGc, LedgerProofsGcConfig}; use crate::protocol::*; use crate::store::traits::proofs::QueryableProofStore; + use crate::store::traits::GetSyncableTxnsAndProofError; use crate::test::{commit_round_updates_until_epoch, create_state_manager}; - use crate::traits::GetSyncableTxnsAndProofError; use crate::{StateManagerConfig, StateVersion}; use std::time::Duration; diff --git a/core-rust/state-manager/src/store/rocks_db.rs b/core-rust/state-manager/src/store/rocks_db.rs index 520ae438c9..d4775a6f4b 100644 --- a/core-rust/state-manager/src/store/rocks_db.rs +++ b/core-rust/state-manager/src/store/rocks_db.rs @@ -63,50 +63,39 @@ */ use std::collections::HashSet; -use std::fmt; - -use crate::engine_prelude::*; -use crate::store::traits::*; -use crate::{ - BySubstate, CommittedTransactionIdentifiers, LedgerProof, LedgerProofOrigin, - LedgerTransactionReceipt, LocalTransactionExecution, LocalTransactionReceipt, ReceiptTreeHash, - StateVersion, SubstateChangeAction, TransactionTreeHash, - VersionedCommittedTransactionIdentifiers, VersionedLedgerProof, - VersionedLedgerTransactionReceipt, VersionedLocalTransactionExecution, -}; -use node_common::utils::IsAccountExt; -use rocksdb::checkpoint::Checkpoint; -use rocksdb::{ - AsColumnFamilyRef, ColumnFamily, ColumnFamilyDescriptor, DBPinnableSlice, Direction, - IteratorMode, Options, Snapshot, WriteBatch, DB, -}; - use std::path::PathBuf; -use node_common::locks::Snapshottable; +use node_common::rocksdb::{ColumnFamilyDescriptor, Direction, IteratorMode, Options, DB}; use tracing::{error, info, warn}; +use node_common::locks::Snapshottable; +use node_common::utils::IsAccountExt; + use crate::accumulator_tree::storage::{ReadableAccuTreeStore, TreeSlice}; +use crate::engine_prelude::*; use crate::query::TransactionIdentifierLoader; -use crate::store::codecs::*; +use crate::store::column_families::*; use crate::store::historical_state::StateTreeBasedSubstateDatabase; -use crate::store::traits::gc::{ - LedgerProofsGcProgress, LedgerProofsGcStore, StateTreeGcStore, VersionedLedgerProofsGcProgress, -}; +use crate::store::traits::extensions::*; +use crate::store::traits::gc::{LedgerProofsGcProgress, LedgerProofsGcStore, StateTreeGcStore}; use crate::store::traits::indices::{ - CreationId, EntityBlueprintId, EntityListingIndex, ObjectBlueprintName, ObjectBlueprintNameV1, - VersionedEntityBlueprintId, VersionedObjectBlueprintName, + CreationId, EntityBlueprintId, EntityListingIndex, ObjectBlueprintNameV1, }; use crate::store::traits::measurement::{CategoryDbVolumeStatistic, MeasurableDatabase}; use crate::store::traits::scenario::{ - ExecutedScenario, ExecutedScenarioStore, ScenarioSequenceNumber, VersionedExecutedScenario, + ExecutedScenario, ExecutedScenarioStore, ScenarioSequenceNumber, }; -use crate::store::typed_cf_api::*; +use crate::store::traits::*; use crate::transaction::{ LedgerTransactionHash, RawLedgerTransaction, TypedTransactionIdentifiers, }; - -use super::traits::extensions::*; +use crate::{ + BySubstate, CommittedTransactionIdentifiers, LedgerProof, LedgerProofOrigin, + LedgerTransactionReceipt, LocalTransactionExecution, LocalTransactionReceipt, ReceiptTreeHash, + StateVersion, SubstateChangeAction, TransactionTreeHash, +}; +use node_common::store::rocks_db::*; +use node_common::store::typed_cf_api::*; /// A listing of all column family names used by the Node. /// @@ -126,7 +115,7 @@ use super::traits::extensions::*; /// The `NAME` constants defined by `*Cf` structs (and referenced below) are used as database column /// family names. Any change would effectively mean a ledger wipe. For this reason, we choose to /// define them manually (rather than using the `Into`, which is refactor-sensitive). -const ALL_COLUMN_FAMILIES: [&str; 25] = [ +const ALL_STATE_MANAGER_COLUMN_FAMILIES: [&str; 25] = [ RawLedgerTransactionsCf::DEFAULT_NAME, CommittedTransactionIdentifiersCf::VERSIONED_NAME, TransactionReceiptsCf::VERSIONED_NAME, @@ -154,591 +143,6 @@ const ALL_COLUMN_FAMILIES: [&str; 25] = [ BlueprintAndCreationIndexedObjectsCf::VERSIONED_NAME, ]; -/// Committed transactions. -/// Schema: `StateVersion.to_bytes()` -> `RawLedgerTransaction.as_ref::<[u8]>()` -/// Note: This table does not use explicit versioning wrapper, since the serialized content of -/// [`RawLedgerTransaction`] is itself versioned. -struct RawLedgerTransactionsCf; -impl DefaultCf for RawLedgerTransactionsCf { - type Key = StateVersion; - type Value = RawLedgerTransaction; - - const DEFAULT_NAME: &'static str = "raw_ledger_transactions"; - type KeyCodec = StateVersionDbCodec; - type ValueCodec = RawLedgerTransactionDbCodec; -} - -/// Identifiers of committed transactions. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedCommittedTransactionIdentifiers)` -struct CommittedTransactionIdentifiersCf; -impl VersionedCf for CommittedTransactionIdentifiersCf { - type Key = StateVersion; - type Value = CommittedTransactionIdentifiers; - - const VERSIONED_NAME: &'static str = "committed_transaction_identifiers"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedCommittedTransactionIdentifiers; -} - -/// Ledger receipts of committed transactions. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerTransactionReceipt)` -struct TransactionReceiptsCf; -impl VersionedCf for TransactionReceiptsCf { - type Key = StateVersion; - type Value = LedgerTransactionReceipt; - - const VERSIONED_NAME: &'static str = "transaction_receipts"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedLedgerTransactionReceipt; -} - -/// Off-ledger details of committed transaction results (stored only when configured via -/// `enable_local_transaction_execution_index`). -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLocalTransactionExecution)` -struct LocalTransactionExecutionsCf; -impl VersionedCf for LocalTransactionExecutionsCf { - type Key = StateVersion; - type Value = LocalTransactionExecution; - - const VERSIONED_NAME: &'static str = "local_transaction_executions"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedLocalTransactionExecution; -} - -/// Ledger proofs of committed transactions. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` -struct LedgerProofsCf; -impl VersionedCf for LedgerProofsCf { - type Key = StateVersion; - type Value = LedgerProof; - - const VERSIONED_NAME: &'static str = "ledger_proofs"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedLedgerProof; -} - -/// Ledger proofs of new epochs - i.e. the proofs which trigger the given `next_epoch`. -/// Schema: `Epoch.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` -/// Note: This duplicates a small subset of [`LedgerProofsCf`]'s values. -struct EpochLedgerProofsCf; -impl VersionedCf for EpochLedgerProofsCf { - type Key = Epoch; - type Value = LedgerProof; - - const VERSIONED_NAME: &'static str = "epoch_ledger_proofs"; - type KeyCodec = EpochDbCodec; - type VersionedValue = VersionedLedgerProof; -} - -/// Ledger proofs that initialize protocol updates, i.e. proofs of Consensus `origin`, -/// with headers containing a non-empty `next_protocol_version`. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` -/// Note: This duplicates a small subset of [`LedgerProofsCf`]'s values. -struct ProtocolUpdateInitLedgerProofsCf; -impl VersionedCf for ProtocolUpdateInitLedgerProofsCf { - type Key = StateVersion; - type Value = LedgerProof; - - const VERSIONED_NAME: &'static str = "protocol_update_init_ledger_proofs"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedLedgerProof; -} - -/// Ledger proofs of ProtocolUpdate `origin`, i.e. proofs created locally -/// while protocol update state modifications were being applied. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedLedgerProof)` -/// Note: This duplicates a small subset of [`LedgerProofsCf`]'s values. -struct ProtocolUpdateExecutionLedgerProofsCf; -impl VersionedCf for ProtocolUpdateExecutionLedgerProofsCf { - type Key = StateVersion; - type Value = LedgerProof; - - const VERSIONED_NAME: &'static str = "protocol_update_execution_ledger_proofs"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedLedgerProof; -} - -/// DB "index" table for transaction's [`IntentHash`] resolution. -/// Schema: `IntentHash.as_ref::<[u8]>()` -> `StateVersion.to_bytes()` -/// Note: This table does not use explicit versioning wrapper, since the value represents a DB -/// key of another table (and versioning DB keys is not useful). -struct IntentHashesCf; -impl DefaultCf for IntentHashesCf { - type Key = IntentHash; - type Value = StateVersion; - - const DEFAULT_NAME: &'static str = "intent_hashes"; - type KeyCodec = HashDbCodec; - type ValueCodec = StateVersionDbCodec; -} - -/// DB "index" table for transaction's [`NotarizedTransactionHash`] resolution. -/// Schema: `NotarizedTransactionHash.as_ref::<[u8]>()` -> `StateVersion.to_bytes()` -/// Note: This table does not use explicit versioning wrapper, since the value represents a DB -/// key of another table (and versioning DB keys is not useful). -struct NotarizedTransactionHashesCf; -impl DefaultCf for NotarizedTransactionHashesCf { - type Key = NotarizedTransactionHash; - type Value = StateVersion; - - const DEFAULT_NAME: &'static str = "notarized_transaction_hashes"; - type KeyCodec = HashDbCodec; - type ValueCodec = StateVersionDbCodec; -} - -/// DB "index" table for transaction's [`LedgerTransactionHash`] resolution. -/// Schema: `LedgerTransactionHash.as_ref::<[u8]>()` -> `StateVersion.to_bytes()` -/// Note: This table does not use explicit versioning wrapper, since the value represents a DB -/// key of another table (and versioning DB keys is not useful). -struct LedgerTransactionHashesCf; -impl DefaultCf for LedgerTransactionHashesCf { - type Key = LedgerTransactionHash; - type Value = StateVersion; - - const DEFAULT_NAME: &'static str = "ledger_transaction_hashes"; - type KeyCodec = HashDbCodec; - type ValueCodec = StateVersionDbCodec; -} - -/// Radix Engine's runtime Substate database. -/// Schema: `encode_to_rocksdb_bytes(DbPartitionKey, DbSortKey)` -> `Vec` -/// Note: This table does not use explicit versioning wrapper, since each serialized substate -/// value is already versioned. -struct SubstatesCf; -impl DefaultCf for SubstatesCf { - type Key = DbSubstateKey; - type Value = DbSubstateValue; - - const DEFAULT_NAME: &'static str = "substates"; - type KeyCodec = SubstateKeyDbCodec; - type ValueCodec = DirectDbCodec; -} - -/// Ancestor information for the RE Nodes of [`Substates`] (which is useful and can be computed, -/// but is not provided by the Engine itself). -/// Schema: `NodeId.0` -> `scrypto_encode(VersionedSubstateNodeAncestryRecord)` -/// Note: we do not persist records of root Nodes (which do not have any ancestor). -struct SubstateNodeAncestryRecordsCf; -impl VersionedCf for SubstateNodeAncestryRecordsCf { - type Key = NodeId; - type Value = SubstateNodeAncestryRecord; - - const VERSIONED_NAME: &'static str = "substate_node_ancestry_records"; - type KeyCodec = NodeIdDbCodec; - type VersionedValue = VersionedSubstateNodeAncestryRecord; -} - -/// Vertex store. -/// Schema: `[]` -> `scrypto_encode(VersionedVertexStoreBlob)` -/// Note: This is a single-entry table (i.e. the empty key is the only allowed key). -struct VertexStoreCf; -impl VersionedCf for VertexStoreCf { - type Key = (); - type Value = VertexStoreBlob; - - const VERSIONED_NAME: &'static str = "vertex_store"; - type KeyCodec = UnitDbCodec; - type VersionedValue = VersionedVertexStoreBlob; -} - -/// Individual nodes of the Substate database's hash tree. -/// Schema: `encode_key(StoredTreeNodeKey)` -> `scrypto_encode(VersionedTreeNode)`. -struct StateTreeNodesCf; -impl VersionedCf for StateTreeNodesCf { - type Key = StoredTreeNodeKey; - type Value = TreeNode; - - // Note: the legacy `state_hash_tree` name lives on here because it already got persisted. - const VERSIONED_NAME: &'static str = "state_hash_tree_nodes"; - type KeyCodec = StoredTreeNodeKeyDbCodec; - type VersionedValue = VersionedTreeNode; -} - -/// Parts of the Substate database's hash tree that became stale at a specific state version. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedStaleTreeParts)`. -struct StaleStateTreePartsCf; -impl VersionedCf for StaleStateTreePartsCf { - type Key = StateVersion; - type Value = StaleTreeParts; - - // Note: the legacy `state_hash_tree` name lives on here because it already got persisted. - const VERSIONED_NAME: &'static str = "stale_state_hash_tree_parts"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedStaleTreeParts; -} - -/// Transaction accumulator tree slices added at a specific state version. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedTransactionAccuTreeSlice)`. -struct TransactionAccuTreeSlicesCf; -impl VersionedCf for TransactionAccuTreeSlicesCf { - type Key = StateVersion; - type Value = TransactionAccuTreeSlice; - - const VERSIONED_NAME: &'static str = "transaction_accu_tree_slices"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedTransactionAccuTreeSlice; -} - -/// Receipt accumulator tree slices added at a specific state version. -/// Schema: `StateVersion.to_bytes()` -> `scrypto_encode(VersionedReceiptAccuTreeSlice)`. -struct ReceiptAccuTreeSlicesCf; -impl VersionedCf for ReceiptAccuTreeSlicesCf { - type Key = StateVersion; - type Value = ReceiptAccuTreeSlice; - - const VERSIONED_NAME: &'static str = "receipt_accu_tree_slices"; - type KeyCodec = StateVersionDbCodec; - type VersionedValue = VersionedReceiptAccuTreeSlice; -} - -/// Various data needed by extensions. -/// Schema: `ExtensionsDataKeys.to_string().as_bytes() -> Vec`. -/// Note: This table does not use explicit versioning wrapper, since each extension manages the -/// serialization of their data (of its custom type). -struct ExtensionsDataCf; -impl TypedCf for ExtensionsDataCf { - type Key = ExtensionsDataKey; - type Value = Vec; - - type KeyCodec = PredefinedDbCodec; - type ValueCodec = DirectDbCodec; - - const NAME: &'static str = "extensions_data"; - - fn key_codec(&self) -> PredefinedDbCodec { - PredefinedDbCodec::new_from_string_representations(vec![ - ExtensionsDataKey::AccountChangeIndexEnabled, - ExtensionsDataKey::AccountChangeIndexLastProcessedStateVersion, - ExtensionsDataKey::LocalTransactionExecutionIndexEnabled, - ExtensionsDataKey::December2023LostSubstatesRestored, - ExtensionsDataKey::StateTreeAssociatedValuesStatus, - ExtensionsDataKey::EntityListingIndicesLastProcessedStateVersion, - ]) - } - - fn value_codec(&self) -> DirectDbCodec { - DirectDbCodec::default() - } -} - -/// Account addresses and state versions at which they were changed. -/// Schema: `[GlobalAddress.0, StateVersion.to_bytes()].concat() -> []`. -/// Note: This is a key-only table (i.e. the empty value is the only allowed value). Given fast -/// prefix iterator from RocksDB this emulates a `Map>`. -struct AccountChangeStateVersionsCf; -impl TypedCf for AccountChangeStateVersionsCf { - type Key = (GlobalAddress, StateVersion); - type Value = (); - - type KeyCodec = PrefixGlobalAddressDbCodec; - type ValueCodec = UnitDbCodec; - - const NAME: &'static str = "account_change_state_versions"; - - fn key_codec(&self) -> PrefixGlobalAddressDbCodec { - PrefixGlobalAddressDbCodec::new(StateVersionDbCodec::default()) - } - - fn value_codec(&self) -> UnitDbCodec { - UnitDbCodec::default() - } -} - -/// Additional details of "Scenarios" (and their transactions) executed as part of Genesis, -/// keyed by their sequence number (i.e. their index in the list of Scenarios to execute). -/// Schema: `ScenarioSequenceNumber.to_be_bytes()` -> `scrypto_encode(VersionedExecutedScenario)` -struct ExecutedScenariosCf; -impl VersionedCf for ExecutedScenariosCf { - type Key = ScenarioSequenceNumber; - type Value = ExecutedScenario; - - // Note: a legacy name is still used here, even though we now have scenarios run outside Genesis - const VERSIONED_NAME: &'static str = "executed_genesis_scenarios"; - type KeyCodec = ScenarioSequenceNumberDbCodec; - type VersionedValue = VersionedExecutedScenario; -} - -/// A progress of the GC process pruning the [`LedgerProofsCf`]. -/// Schema: `[]` -> `scrypto_encode(VersionedLedgerProofsGcProgress)` -/// Note: This is a single-entry table (i.e. the empty key is the only allowed key). -struct LedgerProofsGcProgressCf; -impl VersionedCf for LedgerProofsGcProgressCf { - type Key = (); - type Value = LedgerProofsGcProgress; - - const VERSIONED_NAME: &'static str = "ledger_proofs_gc_progress"; - type KeyCodec = UnitDbCodec; - type VersionedValue = VersionedLedgerProofsGcProgress; -} - -/// Node IDs and blueprints of all entities, indexed by their type and creation order. -/// Schema: `[EntityType as u8, StateVersion.to_be_bytes(), (index_within_txn as u32).to_be_bytes()].concat()` -> `scrypto_encode(VersionedEntityBlueprintId)` -struct TypeAndCreationIndexedEntitiesCf; -impl VersionedCf for TypeAndCreationIndexedEntitiesCf { - type Key = (EntityType, CreationId); - type Value = EntityBlueprintId; - - const VERSIONED_NAME: &'static str = "type_and_creation_indexed_entities"; - type KeyCodec = TypeAndCreationIndexKeyDbCodec; - type VersionedValue = VersionedEntityBlueprintId; -} - -/// Node IDs and blueprints of all objects, indexed by their blueprint ID and creation order. -/// Schema: `[PackageAddress.0, hash(blueprint_name), StateVersion.to_be_bytes(), (index_within_txn as u32).to_be_bytes()].concat()` -> `scrypto_encode(VersionedObjectBlueprintName)` -struct BlueprintAndCreationIndexedObjectsCf; -impl VersionedCf for BlueprintAndCreationIndexedObjectsCf { - type Key = (PackageAddress, Hash, CreationId); - type Value = ObjectBlueprintName; - - const VERSIONED_NAME: &'static str = "blueprint_and_creation_indexed_objects"; - type KeyCodec = BlueprintAndCreationIndexKeyDbCodec; - type VersionedValue = VersionedObjectBlueprintName; -} - -/// Substate values associated with leaf nodes of the state hash tree's Substate Tier. -/// Needed for [`LeafSubstateValueStore`]. -/// Note: This table does not use explicit versioning wrapper, since each serialized substate -/// value is already versioned. -struct AssociatedStateTreeValuesCf; -impl DefaultCf for AssociatedStateTreeValuesCf { - type Key = StoredTreeNodeKey; - type Value = DbSubstateValue; - - const DEFAULT_NAME: &'static str = "associated_state_tree_values"; - type KeyCodec = StoredTreeNodeKeyDbCodec; - type ValueCodec = DirectDbCodec; -} - -/// An enum key for [`ExtensionsDataCf`]. -#[derive(Eq, PartialEq, Hash, PartialOrd, Ord, Clone, Debug)] -enum ExtensionsDataKey { - AccountChangeIndexLastProcessedStateVersion, - AccountChangeIndexEnabled, - LocalTransactionExecutionIndexEnabled, - December2023LostSubstatesRestored, - StateTreeAssociatedValuesStatus, - EntityListingIndicesLastProcessedStateVersion, -} - -// IMPORTANT NOTE: the strings defined below are used as database identifiers. Any change would -// effectively clear the associated extension's state in DB. For this reason, we choose to -// define them manually (rather than using the enum's `Into`, which is refactor-sensitive). -impl fmt::Display for ExtensionsDataKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let str = match self { - Self::AccountChangeIndexLastProcessedStateVersion => { - "account_change_index_last_processed_state_version" - } - Self::AccountChangeIndexEnabled => "account_change_index_enabled", - Self::LocalTransactionExecutionIndexEnabled => { - "local_transaction_execution_index_enabled" - } - Self::December2023LostSubstatesRestored => "december_2023_lost_substates_restored", - Self::StateTreeAssociatedValuesStatus => "state_tree_associated_values_status", - Self::EntityListingIndicesLastProcessedStateVersion => { - "entity_listing_indices_last_processed_state_version" - } - }; - write!(f, "{str}") - } -} - -/// A redefined RocksDB's "key and value bytes" tuple (the original one lives in a private module). -pub type KVBytes = (Box<[u8]>, Box<[u8]>); - -/// A trait capturing the common read methods present both in a "direct" RocksDB instance and in its -/// snapshots. -/// -/// The library we use (a thin C wrapper, really) does not introduce this trivial and natural trait -/// itself, while we desperately need it to abstract the DB-reading code from the actual source of -/// data. -/// -/// A note on changed error handling: -/// The original methods typically return [`Result`]s. Our trait assumes panics instead, since we -/// treat all database access errors as fatal anyways. -pub trait ReadableRocks { - /// Resolves the column family by name. - fn cf_handle(&self, name: &str) -> &ColumnFamily; - - /// Starts iteration over key-value pairs, according to the given [`IteratorMode`]. - fn iterator_cf( - &self, - cf: &impl AsColumnFamilyRef, - mode: IteratorMode, - ) -> Box + '_>; - - /// Gets a single value by key. - fn get_pinned_cf( - &self, - cf: &impl AsColumnFamilyRef, - key: impl AsRef<[u8]>, - ) -> Option; - - /// Gets multiple values by keys. - /// - /// Syntax note: - /// The `<'a>` here is not special at all: it could technically be 100% inferred. Just the - /// compiler feature allowing to skip it from within the `` is not yet stable. - /// TODO(when the rustc feature mentioned above becomes stable): get rid of the `<'a>`. - fn multi_get_cf<'a>( - &'a self, - keys: impl IntoIterator)>, - ) -> Vec>>; -} - -/// A write-supporting extension of the [`ReadableRocks`]. -/// -/// Naturally, it is expected that only a "direct" RocksDB instance can implement this one. -pub trait WriteableRocks: ReadableRocks { - /// Atomically writes the given batch of updates. - fn write(&self, batch: WriteBatch); - - /// Returns a snapshot of the current state. - fn snapshot(&self) -> SnapshotRocks; -} - -/// A [`ReadableRocks`] instance opened as secondary instance. -pub trait SecondaryRocks: ReadableRocks { - /// Tries to catch up with the primary by reading as much as possible from the - /// log files. - fn try_catchup_with_primary(&self); -} - -/// RocksDB checkpoint support. -pub trait CheckpointableRocks { - fn create_checkpoint(&self, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error>; -} - -/// Direct RocksDB instance. -pub struct DirectRocks { - db: DB, -} - -impl ReadableRocks for DirectRocks { - fn cf_handle(&self, name: &str) -> &ColumnFamily { - self.db.cf_handle(name).expect(name) - } - - fn iterator_cf( - &self, - cf: &impl AsColumnFamilyRef, - mode: IteratorMode, - ) -> Box + '_> { - Box::new( - self.db - .iterator_cf(cf, mode) - .map(|result| result.expect("reading from DB iterator")), - ) - } - - fn get_pinned_cf( - &self, - cf: &impl AsColumnFamilyRef, - key: impl AsRef<[u8]>, - ) -> Option { - self.db.get_pinned_cf(cf, key).expect("DB get by key") - } - - fn multi_get_cf<'a>( - &'a self, - keys: impl IntoIterator)>, - ) -> Vec>> { - self.db - .multi_get_cf(keys) - .into_iter() - .map(|result| result.expect("batch DB get by key")) - .collect() - } -} - -impl WriteableRocks for DirectRocks { - fn write(&self, batch: WriteBatch) { - self.db.write(batch).expect("DB write batch"); - } - - fn snapshot(&self) -> SnapshotRocks { - SnapshotRocks { - db: &self.db, - snapshot: self.db.snapshot(), - } - } -} - -impl SecondaryRocks for DirectRocks { - fn try_catchup_with_primary(&self) { - self.db - .try_catch_up_with_primary() - .expect("secondary DB catchup"); - } -} - -impl CheckpointableRocks for DirectRocks { - fn create_checkpoint(&self, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error> { - create_checkpoint(&self.db, checkpoint_path) - } -} - -impl<'db> CheckpointableRocks for SnapshotRocks<'db> { - fn create_checkpoint(&self, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error> { - create_checkpoint(self.db, checkpoint_path) - } -} - -fn create_checkpoint(db: &DB, checkpoint_path: PathBuf) -> Result<(), rocksdb::Error> { - let checkpoint = Checkpoint::new(db)?; - checkpoint.create_checkpoint(checkpoint_path)?; - Ok(()) -} - -/// Snapshot of RocksDB. -/// -/// Implementation note: -/// The original [`DB`] reference is interestingly kept internally by the [`Snapshot`] as well. -/// However, we need direct access to it for the [`Self::cf_handle()`] reasons. -pub struct SnapshotRocks<'db> { - db: &'db DB, - snapshot: Snapshot<'db>, -} - -impl<'db> ReadableRocks for SnapshotRocks<'db> { - fn cf_handle(&self, name: &str) -> &ColumnFamily { - self.db.cf_handle(name).expect(name) - } - - fn iterator_cf( - &self, - cf: &impl AsColumnFamilyRef, - mode: IteratorMode, - ) -> Box + '_> { - Box::new( - self.snapshot - .iterator_cf(cf, mode) - .map(|result| result.expect("reading from snapshot DB iterator")), - ) - } - - fn get_pinned_cf( - &self, - cf: &impl AsColumnFamilyRef, - key: impl AsRef<[u8]>, - ) -> Option { - self.snapshot - .get_pinned_cf(cf, key) - .expect("snapshot DB get by key") - } - - fn multi_get_cf<'a>( - &'a self, - keys: impl IntoIterator)>, - ) -> Vec>> { - self.snapshot - .multi_get_cf(keys) - .into_iter() - .map(|result| result.expect("batch snapshot DB get by key")) - .collect() - } -} - pub type ActualStateManagerDatabase = StateManagerDatabase; impl<'db> Snapshottable<'db> for StateManagerDatabase { @@ -782,7 +186,7 @@ impl ActualStateManagerDatabase { db_opts.create_if_missing(true); db_opts.create_missing_column_families(true); - let column_families: Vec = ALL_COLUMN_FAMILIES + let column_families: Vec = ALL_STATE_MANAGER_COLUMN_FAMILIES .iter() .map(|cf| ColumnFamilyDescriptor::new(cf.to_string(), Options::default())) .collect(); @@ -819,7 +223,7 @@ impl ActualStateManagerDatabase { db_opts.create_if_missing(false); db_opts.create_missing_column_families(false); - let column_families: Vec = ALL_COLUMN_FAMILIES + let column_families: Vec = ALL_STATE_MANAGER_COLUMN_FAMILIES .iter() .map(|cf| ColumnFamilyDescriptor::new(cf.to_string(), Options::default())) .collect(); @@ -1071,7 +475,7 @@ impl ConfigurableDatabase for StateManagerDatabase { impl MeasurableDatabase for ActualStateManagerDatabase { fn get_data_volume_statistics(&self) -> Vec { - let mut statistics = ALL_COLUMN_FAMILIES + let mut statistics = ALL_STATE_MANAGER_COLUMN_FAMILIES .iter() .map(|cf_name| { ( @@ -1080,13 +484,11 @@ impl MeasurableDatabase for ActualStateManagerDatabase { ) }) .collect::>(); - let live_files = match self.rocks.db.live_files() { - Ok(live_files) => live_files, - Err(err) => { - warn!("could not get DB live files; returning 0: {:?}", err); - Vec::new() - } - }; + let live_files = self.rocks.db.live_files().unwrap_or_else(|err| { + warn!("could not get DB live files; returning 0: {:?}", err); + Vec::new() + }); + for live_file in live_files { let Some(statistic) = statistics.get_mut(&live_file.column_family_name) else { warn!("LiveFile of unknown column family: {:?}", live_file); diff --git a/core-rust/state-manager/src/system_executor.rs b/core-rust/state-manager/src/system_executor.rs index e8dc192ad6..0b02dde307 100644 --- a/core-rust/state-manager/src/system_executor.rs +++ b/core-rust/state-manager/src/system_executor.rs @@ -81,8 +81,8 @@ use crate::store::traits::scenario::{ use crate::system_commits::*; use crate::protocol::{ProtocolUpdateNodeBatch, ProtocolVersionName}; -use crate::rocks_db::ActualStateManagerDatabase; -use crate::traits::scenario::ExecutedScenarioV1; +use crate::store::rocks_db::ActualStateManagerDatabase; +use crate::store::traits::scenario::ExecutedScenarioV1; use radix_transaction_scenarios::scenarios::ALL_SCENARIOS; use std::sync::Arc; use std::time::Instant; diff --git a/core-rust/state-manager/src/test/mod.rs b/core-rust/state-manager/src/test/mod.rs index 0d809a9f3e..1fa48508f0 100644 --- a/core-rust/state-manager/src/test/mod.rs +++ b/core-rust/state-manager/src/test/mod.rs @@ -1,6 +1,6 @@ use crate::engine_prelude::*; use crate::query::TransactionIdentifierLoader; -use crate::traits::QueryableProofStore; +use crate::store::traits::QueryableProofStore; use crate::{ CommitRequest, CommitSummary, LedgerHeader, LedgerProof, LedgerProofOrigin, PrepareRequest, PrepareResult, RoundHistory, StateManager, StateManagerConfig, diff --git a/core-rust/state-manager/src/transaction/preparation.rs b/core-rust/state-manager/src/transaction/preparation.rs index edba315b88..f6facf6d00 100644 --- a/core-rust/state-manager/src/transaction/preparation.rs +++ b/core-rust/state-manager/src/transaction/preparation.rs @@ -72,7 +72,7 @@ use tracing::{debug, info}; use crate::engine_prelude::*; use crate::limits::*; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::*; use crate::system_commits::*; diff --git a/core-rust/state-manager/src/transaction/preview.rs b/core-rust/state-manager/src/transaction/preview.rs index 0c94867038..eeb0e5264b 100644 --- a/core-rust/state-manager/src/transaction/preview.rs +++ b/core-rust/state-manager/src/transaction/preview.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use crate::historical_state::{StateHistoryError, VersionScopingSupport}; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::transaction::*; use crate::{ GlobalBalanceSummary, LedgerStateChanges, LedgerStateSummary, PreviewRequest, diff --git a/core-rust/state-manager/src/transaction/validation.rs b/core-rust/state-manager/src/transaction/validation.rs index 06e97b3514..21b8b7e6d1 100644 --- a/core-rust/state-manager/src/transaction/validation.rs +++ b/core-rust/state-manager/src/transaction/validation.rs @@ -7,7 +7,7 @@ use crate::engine_prelude::*; use crate::query::StateManagerSubstateQueries; -use crate::rocks_db::ActualStateManagerDatabase; +use crate::store::rocks_db::ActualStateManagerDatabase; use crate::store::traits::transactions::QueryableTransactionStore; use crate::store::traits::{QueryableProofStore, TransactionIndex}; use crate::transaction::{ExecutionConfigurator, TransactionLogic}; diff --git a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/IncreasingValidatorsTest.java b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/IncreasingValidatorsTest.java index 8ec2acd5f8..8b38802e19 100644 --- a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/IncreasingValidatorsTest.java +++ b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/IncreasingValidatorsTest.java @@ -115,7 +115,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), true, - FunctionalRadixNodeModule.SafetyRecoveryConfig.BERKELEY_DB, + FunctionalRadixNodeModule.SafetyRecoveryConfig.REAL, FunctionalRadixNodeModule.ConsensusConfig.of(1000), FunctionalRadixNodeModule.LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomValidatorsTest.java b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomValidatorsTest.java index 4a402f190e..22d84eaae4 100644 --- a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomValidatorsTest.java +++ b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomValidatorsTest.java @@ -118,7 +118,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), true, - FunctionalRadixNodeModule.SafetyRecoveryConfig.BERKELEY_DB, + FunctionalRadixNodeModule.SafetyRecoveryConfig.REAL, FunctionalRadixNodeModule.ConsensusConfig.of(1000), FunctionalRadixNodeModule.LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomVoteDropperTest.java b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomVoteDropperTest.java index de017cfafa..bfa8597392 100644 --- a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomVoteDropperTest.java +++ b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/RandomVoteDropperTest.java @@ -100,7 +100,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), true, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/SanityTest.java b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/SanityTest.java index 91b978709f..c572608802 100644 --- a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/SanityTest.java +++ b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/SanityTest.java @@ -127,7 +127,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), epochs, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger/MultiNodeRecoveryTest.java b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger/MultiNodeRecoveryTest.java index 24442e703b..5d912c97d2 100644 --- a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger/MultiNodeRecoveryTest.java +++ b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger/MultiNodeRecoveryTest.java @@ -134,7 +134,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), this.epochs, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger_sync/MultiNodeRebootTest.java b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger_sync/MultiNodeRebootTest.java index b4bb738c4f..9a92ac92a9 100644 --- a/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger_sync/MultiNodeRebootTest.java +++ b/core/src/integration/java/com/radixdlt/integration/steady_state/deterministic/rev2/consensus_ledger_sync/MultiNodeRebootTest.java @@ -263,7 +263,7 @@ private void runTest( @Test public void restart_all_nodes_intermittently() { - runTest(new MixedLivenessEachRound(random, 0), SafetyRecoveryConfig.BERKELEY_DB); + runTest(new MixedLivenessEachRound(random, 0), SafetyRecoveryConfig.REAL); } @Test @@ -279,15 +279,13 @@ public void restart_all_nodes_intermittently_with_bad_liveness_recovery_should_f () -> runTest( new MixedLivenessEachRound(random, 0), - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, new MockedVertexStoreModule())) .isInstanceOf(DeterministicTest.NeverReachedStateException.class); } @Test public void restart_all_nodes_intermittently_while_f_nodes_down() { - runTest( - new MixedLivenessEachRound(random, (numValidators - 1) / 3), - SafetyRecoveryConfig.BERKELEY_DB); + runTest(new MixedLivenessEachRound(random, (numValidators - 1) / 3), SafetyRecoveryConfig.REAL); } } diff --git a/core/src/integration/java/com/radixdlt/integration/targeted/consensus/EpochTimeoutCertTest.java b/core/src/integration/java/com/radixdlt/integration/targeted/consensus/EpochTimeoutCertTest.java index d382319319..08ab1bb9fd 100644 --- a/core/src/integration/java/com/radixdlt/integration/targeted/consensus/EpochTimeoutCertTest.java +++ b/core/src/integration/java/com/radixdlt/integration/targeted/consensus/EpochTimeoutCertTest.java @@ -132,7 +132,7 @@ public void no_byzantine_event_occurs_on_epoch_tc_event() { test.runUntilMessage( proposalAtRound(ROUNDS_PER_EPOCH + 2), true, - 10 * NUM_NODES * NUM_NODES * ((int) ROUNDS_PER_EPOCH)); + 10 * NUM_NODES * NUM_NODES * ROUNDS_PER_EPOCH); // Run for a while more and verify that no byzantine issues occur test.runForCount(40000); } diff --git a/core/src/integration/java/com/radixdlt/integration/targeted/rev2/recovery/RecoveryAfterTimeoutQuorumTest.java b/core/src/integration/java/com/radixdlt/integration/targeted/rev2/recovery/RecoveryAfterTimeoutQuorumTest.java index 57558f5af6..a7f7940539 100644 --- a/core/src/integration/java/com/radixdlt/integration/targeted/rev2/recovery/RecoveryAfterTimeoutQuorumTest.java +++ b/core/src/integration/java/com/radixdlt/integration/targeted/rev2/recovery/RecoveryAfterTimeoutQuorumTest.java @@ -116,7 +116,7 @@ public void recovery_after_timeout_quorum_test() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), false, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/integration/java/com/radixdlt/integration/targeted/rev2/storage/TransactionDBSizeStressTest.java b/core/src/integration/java/com/radixdlt/integration/targeted/rev2/storage/TransactionDBSizeStressTest.java index a66a6e303d..247b95b820 100644 --- a/core/src/integration/java/com/radixdlt/integration/targeted/rev2/storage/TransactionDBSizeStressTest.java +++ b/core/src/integration/java/com/radixdlt/integration/targeted/rev2/storage/TransactionDBSizeStressTest.java @@ -106,7 +106,7 @@ private DeterministicTest buildTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), false, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/main/java/com/radixdlt/RadixNodeModule.java b/core/src/main/java/com/radixdlt/RadixNodeModule.java index fc9a035560..8f42b60bf1 100644 --- a/core/src/main/java/com/radixdlt/RadixNodeModule.java +++ b/core/src/main/java/com/radixdlt/RadixNodeModule.java @@ -97,7 +97,7 @@ import com.radixdlt.protocol.ProtocolConfig; import com.radixdlt.rev2.NetworkDefinition; import com.radixdlt.rev2.modules.*; -import com.radixdlt.store.NodeStorageLocationFromPropertiesModule; +import com.radixdlt.store.StorageLocationFromPropertiesModule; import com.radixdlt.sync.SyncRelayConfig; import com.radixdlt.transaction.LedgerSyncLimitsConfig; import com.radixdlt.utils.BooleanUtils; @@ -252,7 +252,7 @@ protected void configure() { install(new EpochsSyncModule()); // Storage directory - install(new NodeStorageLocationFromPropertiesModule()); + install(new StorageLocationFromPropertiesModule()); // State Computer var mempoolMaxMemory = properties.get( @@ -390,8 +390,11 @@ protected void configure() { protocolConfig, ScenariosExecutionConfig.resolveForNetwork(network))); + // Persistence + install(new PersistentSafetyStateStoreModule()); + install(new AddressBookModule()); + // Recovery - install(new BerkeleySafetyStoreModule()); install(new EpochsSafetyRecoveryModule()); install(new REv2LedgerRecoveryModule()); install(new REv2ConsensusRecoveryModule()); diff --git a/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapper.java b/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapper.java index 9486e6724b..477b2e7c73 100644 --- a/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapper.java +++ b/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapper.java @@ -149,7 +149,7 @@ private RadixNode bootstrapRadixNode() { .map(Optional::get) .collect(ImmutableSet.toImmutableSet()); - if (distinctGenesisHashes.size() == 0) { + if (distinctGenesisHashes.isEmpty()) { // No genesis was configured throw new RuntimeException( """ diff --git a/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapperModule.java b/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapperModule.java index 96106f18e8..d08a05c9b1 100644 --- a/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapperModule.java +++ b/core/src/main/java/com/radixdlt/bootstrap/RadixNodeBootstrapperModule.java @@ -75,7 +75,7 @@ import com.radixdlt.modules.MetricsModule; import com.radixdlt.networks.Network; import com.radixdlt.store.NodeStorageLocation; -import com.radixdlt.store.NodeStorageLocationFromPropertiesModule; +import com.radixdlt.store.StorageLocationFromPropertiesModule; import com.radixdlt.utils.properties.RuntimeProperties; import java.io.File; import java.util.Optional; @@ -98,7 +98,7 @@ public void configure() { bind(RadixNodeBootstrapper.class).in(Scopes.SINGLETON); install(new MetricsModule()); install(new CryptoModule()); - install(new NodeStorageLocationFromPropertiesModule()); + install(new StorageLocationFromPropertiesModule()); } @Provides diff --git a/core/src/main/java/com/radixdlt/consensus/safety/RocksSafetyStateStore.java b/core/src/main/java/com/radixdlt/consensus/safety/RocksSafetyStateStore.java new file mode 100644 index 0000000000..41405866de --- /dev/null +++ b/core/src/main/java/com/radixdlt/consensus/safety/RocksSafetyStateStore.java @@ -0,0 +1,313 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.consensus.safety; + +import com.google.common.collect.ImmutableSet; +import com.google.common.hash.HashCode; +import com.radixdlt.consensus.*; +import com.radixdlt.consensus.bft.BFTValidator; +import com.radixdlt.consensus.bft.BFTValidatorId; +import com.radixdlt.consensus.bft.Round; +import com.radixdlt.crypto.ECDSASecp256k1Signature; +import com.radixdlt.lang.Option; +import com.radixdlt.safety.*; +import com.radixdlt.utils.UInt192; +import java.util.Optional; +import java.util.stream.Collectors; +import javax.inject.Inject; + +public class RocksSafetyStateStore implements PersistentSafetyStateStore { + private final RocksDbSafetyStore rocksDbSafetyStore; + + @Inject + public RocksSafetyStateStore(RocksDbSafetyStore rocksDbSafetyStore) { + this.rocksDbSafetyStore = rocksDbSafetyStore; + } + + @Override + public void commitState(SafetyState safetyState) { + rocksDbSafetyStore.upsert(toDTO(safetyState)); + } + + @Override + public void close() { + // no-op + } + + @Override + public Optional get() { + return rocksDbSafetyStore.get().map(RocksSafetyStateStore::fromDTO).toOptional(); + } + + public boolean isMigrated() { + return rocksDbSafetyStore.isMigrated(); + } + + public void markAsMigrated() { + rocksDbSafetyStore.markAsMigrated(); + } + + // ------------------------------------------------------------------------------------- + // Conversion to DTO + // ------------------------------------------------------------------------------------- + + private static SafetyStateDTO toDTO(SafetyState safetyState) { + var validatorId = toDTO(safetyState.getValidatorId()); + var round = toDTO(safetyState.getLockedRound()); + var vote = Option.from(safetyState.getLastVote().map(RocksSafetyStateStore::toDTO)); + return new SafetyStateDTO(validatorId, round, vote); + } + + private static VoteDTO toDTO(Vote vote) { + BFTValidatorIdDTO author = toDTO(vote.getAuthor()); + HighQCDTO highQC = toDTO(vote.highQC()); + VoteDataDTO voteData = toDTO(vote.getVoteData()); + long timestamp = vote.getTimestamp(); + ECDSASecp256k1Signature signature = vote.getSignature(); + Option timeoutSignature = Option.from(vote.getTimeoutSignature()); + + return new VoteDTO(author, highQC, voteData, timestamp, signature, timeoutSignature); + } + + private static HighQCDTO toDTO(HighQC highQC) { + return new HighQCDTO( + toDTO(highQC.highestQC()), + toDTO(highQC.highestCommittedQC()), + Option.from(highQC.highestTC().map(RocksSafetyStateStore::toDTO))); + } + + private static TimeoutCertificateDTO toDTO(TimeoutCertificate tc) { + return new TimeoutCertificateDTO( + tc.getEpoch(), toDTO(tc.getRound()), toDTO(tc.getTimestampedSignatures())); + } + + private static QuorumCertificateDTO toDTO(QuorumCertificate quorumCertificate) { + var signatures = toDTO(quorumCertificate.getTimestampedSignatures()); + var voteData = toDTO(quorumCertificate.getVoteData()); + + return new QuorumCertificateDTO(signatures, voteData); + } + + private static TimestampedECDSASignaturesDTO toDTO( + TimestampedECDSASignatures timestampedSignatures) { + return new TimestampedECDSASignaturesDTO( + timestampedSignatures.getSignatures().entrySet().stream() + .collect(Collectors.toMap(e -> toDTO(e.getKey()), e -> toDTO(e.getValue())))); + } + + private static TimestampedECDSASignatureDTO toDTO(TimestampedECDSASignature signature) { + return new TimestampedECDSASignatureDTO(signature.timestamp(), signature.signature()); + } + + private static VoteDataDTO toDTO(VoteData voteData) { + return new VoteDataDTO( + toDTO(voteData.getProposed()), + toDTO(voteData.getParent()), + Option.from(voteData.getCommitted().map(RocksSafetyStateStore::toDTO))); + } + + private static BFTHeaderDTO toDTO(BFTHeader header) { + return new BFTHeaderDTO( + toDTO(header.getRound()), toDTO(header.getVertexId()), toDTO(header.getLedgerHeader())); + } + + private static LedgerHeaderDTO toDTO(com.radixdlt.consensus.LedgerHeader ledgerHeader) { + return new LedgerHeaderDTO( + ledgerHeader.getEpoch(), + toDTO(ledgerHeader.getRound()), + ledgerHeader.getStateVersion(), + toDTO(ledgerHeader.getHashes()), + ledgerHeader.consensusParentRoundTimestamp(), + ledgerHeader.proposerTimestamp(), + ledgerHeader.getNextEpoch().map(RocksSafetyStateStore::toDTO), + ledgerHeader.nextProtocolVersion()); + } + + private static com.radixdlt.statecomputer.commit.LedgerHashes toDTO(LedgerHashes hashes) { + return new com.radixdlt.statecomputer.commit.LedgerHashes( + hashes.getStateRoot(), hashes.getTransactionRoot(), hashes.getReceiptRoot()); + } + + private static NextEpochDTO toDTO(NextEpoch epoch) { + return new NextEpochDTO( + epoch.getEpoch(), + epoch.getValidators().stream().map(RocksSafetyStateStore::toDTO).toList()); + } + + private static BFTValidatorDTO toDTO(BFTValidator bftValidator) { + return new BFTValidatorDTO( + bftValidator.getPower().toBigEndianBytes(), toDTO(bftValidator.getValidatorId())); + } + + private static VertexIdDTO toDTO(HashCode vertexId) { + return new VertexIdDTO(vertexId.asBytes()); + } + + private static BFTValidatorIdDTO toDTO(BFTValidatorId validatorId) { + return new BFTValidatorIdDTO(validatorId.getKey(), validatorId.getValidatorAddress()); + } + + private static RoundDTO toDTO(Round round) { + return new RoundDTO(round.number()); + } + + // ------------------------------------------------------------------------------------- + // Conversion to domain object + // ------------------------------------------------------------------------------------- + + private static SafetyState fromDTO(SafetyStateDTO dto) { + return SafetyState.create( + fromDTO(dto.validatorId()), + fromDTO(dto.round()), + dto.lastVote().map(RocksSafetyStateStore::fromDTO).toOptional()); + } + + private static BFTValidatorId fromDTO(BFTValidatorIdDTO dto) { + return BFTValidatorId.create(dto.validatorAddress(), dto.key()); + } + + private static Round fromDTO(RoundDTO dto) { + return Round.of(dto.round()); + } + + private static Vote fromDTO(VoteDTO dto) { + return new Vote( + fromDTO(dto.author()), + fromDTO(dto.voteData()), + dto.timestamp(), + dto.signature(), + fromDTO(dto.highQC()), + dto.timeoutSignature().toOptional()); + } + + private static VoteData fromDTO(VoteDataDTO dto) { + return new VoteData( + fromDTO(dto.proposed()), + fromDTO(dto.parent()), + dto.committed().map(RocksSafetyStateStore::fromDTO).toNullable()); + } + + private static BFTHeader fromDTO(BFTHeaderDTO dto) { + return new BFTHeader( + fromDTO(dto.round()), fromDTO(dto.vertexId()), fromDTO(dto.ledgerHeader())); + } + + private static HashCode fromDTO(VertexIdDTO dto) { + return HashCode.fromBytes(dto.idBytes()); + } + + private static LedgerHeader fromDTO(LedgerHeaderDTO dto) { + return new LedgerHeader( + dto.epoch(), + fromDTO(dto.round()), + dto.stateVersion(), + fromDTO(dto.hashes()), + dto.consensusParentRoundTimestampMs(), + dto.proposerTimestampMs(), + dto.nextEpoch().map(RocksSafetyStateStore::fromDTO).toNullable(), + dto.nextProtocolVersion().toNullable()); + } + + private static LedgerHashes fromDTO(com.radixdlt.statecomputer.commit.LedgerHashes hashes) { + return LedgerHashes.create(hashes.stateRoot(), hashes.transactionRoot(), hashes.receiptRoot()); + } + + private static NextEpoch fromDTO(NextEpochDTO dto) { + return NextEpoch.create( + dto.epoch(), + dto.validators().stream() + .map(RocksSafetyStateStore::fromDTO) + .collect(ImmutableSet.toImmutableSet())); + } + + private static BFTValidator fromDTO(BFTValidatorDTO dto) { + return BFTValidator.from(fromDTO(dto.validatorId()), UInt192.fromBigEndianBytes(dto.power())); + } + + private static HighQC fromDTO(HighQCDTO dto) { + return HighQC.from( + fromDTO(dto.highestQC()), + fromDTO(dto.highestCommittedQC()), + dto.highestTC().map(RocksSafetyStateStore::fromDTO).toOptional()); + } + + private static QuorumCertificate fromDTO(QuorumCertificateDTO dto) { + return new QuorumCertificate(fromDTO(dto.voteData()), fromDTO(dto.signatures())); + } + + private static TimestampedECDSASignatures fromDTO(TimestampedECDSASignaturesDTO dto) { + return new TimestampedECDSASignatures( + dto.nodeToTimestampedSignature().entrySet().stream() + .collect(Collectors.toMap(e -> fromDTO(e.getKey()), e -> fromDTO(e.getValue())))); + } + + private static TimestampedECDSASignature fromDTO(TimestampedECDSASignatureDTO dto) { + return TimestampedECDSASignature.from(dto.timestamp(), dto.signature()); + } + + private static TimeoutCertificate fromDTO(TimeoutCertificateDTO dto) { + return new TimeoutCertificate(dto.epoch(), fromDTO(dto.round()), fromDTO(dto.signatures())); + } +} diff --git a/core/src/main/java/com/radixdlt/consensus/safety/SafetyState.java b/core/src/main/java/com/radixdlt/consensus/safety/SafetyState.java index 9fd1896fca..afac323ef2 100644 --- a/core/src/main/java/com/radixdlt/consensus/safety/SafetyState.java +++ b/core/src/main/java/com/radixdlt/consensus/safety/SafetyState.java @@ -111,6 +111,11 @@ private SafetyState(BFTValidatorId validatorId, Round lockedRound, Optional lastVote) { + return new SafetyState(validatorId, lockedRound, lastVote); + } + static class Builder { private final SafetyState original; private Round lockedRound; diff --git a/core/src/main/java/com/radixdlt/p2p/P2PModule.java b/core/src/main/java/com/radixdlt/p2p/P2PModule.java index d82e7b2a02..086b01dda9 100644 --- a/core/src/main/java/com/radixdlt/p2p/P2PModule.java +++ b/core/src/main/java/com/radixdlt/p2p/P2PModule.java @@ -71,12 +71,9 @@ import com.radixdlt.crypto.ECDSASecp256k1PublicKey; import com.radixdlt.environment.*; import com.radixdlt.ledger.LedgerProofBundle; -import com.radixdlt.monitoring.Metrics; import com.radixdlt.networks.Network; import com.radixdlt.p2p.addressbook.AddressBook; import com.radixdlt.p2p.addressbook.AddressBookPeerControl; -import com.radixdlt.p2p.addressbook.AddressBookPersistence; -import com.radixdlt.p2p.addressbook.BerkeleyAddressBookStore; import com.radixdlt.p2p.discovery.SeedNodesConfigParser; import com.radixdlt.p2p.hostip.HostIp; import com.radixdlt.p2p.hostip.HostIpModule; @@ -85,10 +82,7 @@ import com.radixdlt.p2p.transport.PeerServerBootstrap; import com.radixdlt.protocol.ProtocolUpdateEnactmentCondition.EnactAtStartOfEpochIfValidatorsReady; import com.radixdlt.protocol.ProtocolUpdateEnactmentCondition.EnactAtStartOfEpochUnconditionally; -import com.radixdlt.serialization.Serialization; import com.radixdlt.statecomputer.ProtocolState; -import com.radixdlt.store.BerkeleyDbDefaults; -import com.radixdlt.store.NodeStorageLocation; import com.radixdlt.utils.properties.RuntimeProperties; public final class P2PModule extends AbstractModule { @@ -111,7 +105,6 @@ protected void configure() { bind(PeersView.class).to(PeerManagerPeersView.class).in(Scopes.SINGLETON); bind(PeerControl.class).to(AddressBookPeerControl.class).in(Scopes.SINGLETON); bind(PeerOutboundBootstrap.class).to(PeerOutboundBootstrapImpl.class).in(Scopes.SINGLETON); - bind(AddressBookPersistence.class).to(BerkeleyAddressBookStore.class); bind(PeerServerBootstrap.class).in(Scopes.SINGLETON); bind(PendingOutboundChannelsManager.class).in(Scopes.SINGLETON); bind(PeerManager.class).in(Scopes.SINGLETON); @@ -158,19 +151,6 @@ public RadixNodeUri selfUri( return RadixNodeUri.fromPubKeyAndAddress(network.getId(), selfKey, host, port); } - @Provides - @Singleton - BerkeleyAddressBookStore addressBookStore( - Serialization serialization, - Metrics metrics, - @NodeStorageLocation String nodeStorageLocation) { - return new BerkeleyAddressBookStore( - serialization, - metrics, - nodeStorageLocation, - BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties)); - } - /** * A start processor that unbans all peers if the node is booting within enactment bounds of an * upcoming protocol update. It is likely that any banned peers have been banned because the node diff --git a/core/src/main/java/com/radixdlt/p2p/RadixNodeUri.java b/core/src/main/java/com/radixdlt/p2p/RadixNodeUri.java index 0a2d30f3db..0591ab6115 100644 --- a/core/src/main/java/com/radixdlt/p2p/RadixNodeUri.java +++ b/core/src/main/java/com/radixdlt/p2p/RadixNodeUri.java @@ -127,7 +127,7 @@ public NodeId getNodeId() { } @JsonValue - private byte[] getSerializedValue() { + public byte[] getSerializedValue() { return getUriString().getBytes(StandardCharsets.UTF_8); } diff --git a/core/src/main/java/com/radixdlt/p2p/addressbook/AddressBookEntry.java b/core/src/main/java/com/radixdlt/p2p/addressbook/AddressBookEntry.java index cf5d061ad6..edced5f5c1 100644 --- a/core/src/main/java/com/radixdlt/p2p/addressbook/AddressBookEntry.java +++ b/core/src/main/java/com/radixdlt/p2p/addressbook/AddressBookEntry.java @@ -393,6 +393,10 @@ public boolean failedHandshakeIsEmptyOrExpired() { return maybeFailedHandshake.isEmpty() || maybeFailedHandshake.get().isExpired(); } + public Optional getMaybeFailedHandshake() { + return maybeFailedHandshake; + } + @JsonProperty("latestConnectionStatus") @DsonOutput(DsonOutput.Output.ALL) private String getLatestConnectionStatusForSerializer() { diff --git a/core/src/main/java/com/radixdlt/p2p/addressbook/BerkeleyAddressBookStore.java b/core/src/main/java/com/radixdlt/p2p/addressbook/BerkeleyAddressBookStore.java index 53f8dc732d..07a08ff37d 100644 --- a/core/src/main/java/com/radixdlt/p2p/addressbook/BerkeleyAddressBookStore.java +++ b/core/src/main/java/com/radixdlt/p2p/addressbook/BerkeleyAddressBookStore.java @@ -300,9 +300,5 @@ public static final class BerkeleyAddressBookStoreException extends RuntimeExcep public BerkeleyAddressBookStoreException(String message) { super(message); } - - public BerkeleyAddressBookStoreException(String message, Throwable cause) { - super(message, cause); - } } } diff --git a/core/src/main/java/com/radixdlt/p2p/addressbook/RocksAddressBookStore.java b/core/src/main/java/com/radixdlt/p2p/addressbook/RocksAddressBookStore.java new file mode 100644 index 0000000000..f423873db0 --- /dev/null +++ b/core/src/main/java/com/radixdlt/p2p/addressbook/RocksAddressBookStore.java @@ -0,0 +1,221 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p.addressbook; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.radixdlt.lang.Option; +import com.radixdlt.p2p.*; +import com.radixdlt.serialization.DeserializeException; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.List; +import java.util.Set; +import javax.inject.Inject; + +public class RocksAddressBookStore implements AddressBookPersistence { + private final RocksDbAddressBookStore addressBookStore; + private final RocksDbHighPriorityPeersStore highPriorityPeersStore; + + @Inject + public RocksAddressBookStore( + RocksDbAddressBookStore addressBookStore, + RocksDbHighPriorityPeersStore highPriorityPeersStore) { + this.addressBookStore = addressBookStore; + this.highPriorityPeersStore = highPriorityPeersStore; + } + + public void open() { + // no-op + } + + public void close() { + // no-op + } + + public void reset() { + addressBookStore.reset(); + highPriorityPeersStore.reset(); + } + + public boolean upsertEntry(AddressBookEntry entry) { + return addressBookStore.upsertEntry(toDTO(entry)); + } + + public boolean removeEntry(NodeId nodeId) { + return addressBookStore.removeEntry(toDTO(nodeId)); + } + + public ImmutableList getAllEntries() { + return ImmutableList.copyOf( + addressBookStore.getAllEntries().stream().map(RocksAddressBookStore::fromDTO).iterator()); + } + + public void storeHighPriorityPeers(List ids) { + highPriorityPeersStore.storeHighPriorityPeers( + ids.stream().map(RocksAddressBookStore::toDTO).collect(ImmutableList.toImmutableList())); + } + + public List getHighPriorityPeers() { + return highPriorityPeersStore.getHighPriorityPeers().stream() + .map(RocksAddressBookStore::fromDTO) + .collect(ImmutableList.toImmutableList()); + } + + public boolean isMigrated() { + return addressBookStore.isMigrated(); + } + + public void markAsMigrated() { + addressBookStore.markAsMigrated(); + } + + private static AddressBookEntryDTO toDTO(AddressBookEntry entry) { + return new AddressBookEntryDTO( + new NodeIdDTO(entry.getNodeId().getPublicKey()), + Option.from(entry.bannedUntil().map(Instant::toEpochMilli)), + toDTO(entry.getKnownAddresses())); + } + + private static AddressBookEntry fromDTO(AddressBookEntryDTO dto) { + return new AddressBookEntry( + NodeId.fromPublicKey(dto.nodeId().publicKey()), + dto.bannedUntil().map(Instant::ofEpochMilli).toOptional(), + fromDTO(dto.knownAddresses())); + } + + private static NodeIdDTO toDTO(NodeId nodeId) { + return new NodeIdDTO(nodeId.getPublicKey()); + } + + private static NodeId fromDTO(NodeIdDTO dto) { + return NodeId.fromPublicKey(dto.publicKey()); + } + + private static PeerAddressEntryDTO toDTO(AddressBookEntry.PeerAddressEntry entry) { + var connectionStatus = + entry.getLatestConnectionStatus().map(RocksAddressBookStore::toConnectionStatus); + + var instant = + entry + .getMaybeFailedHandshake() + .map(AddressBookEntry.PeerAddressEntry.FailedHandshake::retainUntil) + .map(Instant::toEpochMilli); + return new PeerAddressEntryDTO( + entry.getUri().getSerializedValue(), Option.from(connectionStatus), Option.from(instant)); + } + + private static PeerAddressEntryDTO.ConnectionStatus toConnectionStatus( + AddressBookEntry.PeerAddressEntry.LatestConnectionStatus status) { + return switch (status) { + case SUCCESS -> PeerAddressEntryDTO.ConnectionStatus.SUCCESS; + case FAILURE -> PeerAddressEntryDTO.ConnectionStatus.FAILURE; + }; + } + + private static AddressBookEntry.PeerAddressEntry fromDTO(PeerAddressEntryDTO dto) { + return new AddressBookEntry.PeerAddressEntry( + deserializeRadixNodeUri(dto), + dto.latestConnectionStatus() + .map(RocksAddressBookStore::toLatestConnectionStatus) + .toOptional(), + dto.maybeFailedHandshake() + .map(Instant::ofEpochMilli) + .map(AddressBookEntry.PeerAddressEntry.FailedHandshake::new) + .toOptional()); + } + + private static AddressBookEntry.PeerAddressEntry.LatestConnectionStatus toLatestConnectionStatus( + PeerAddressEntryDTO.ConnectionStatus status) { + if (status instanceof PeerAddressEntryDTO.ConnectionStatus.Success) { + return AddressBookEntry.PeerAddressEntry.LatestConnectionStatus.SUCCESS; + } + if (status instanceof PeerAddressEntryDTO.ConnectionStatus.Failure) { + return AddressBookEntry.PeerAddressEntry.LatestConnectionStatus.FAILURE; + } + throw new IllegalStateException("Unknown connection status: " + status); + } + + private static RadixNodeUri deserializeRadixNodeUri(PeerAddressEntryDTO dto) { + RadixNodeUri nodeUri; + try { + nodeUri = RadixNodeUri.deserialize(dto.address()); + } catch (URISyntaxException | DeserializeException e) { + throw new RuntimeException(e); + } + return nodeUri; + } + + private static Set toDTO(Set input) { + return input.stream().map(RocksAddressBookStore::toDTO).collect(ImmutableSet.toImmutableSet()); + } + + private static ImmutableSet fromDTO( + Set input) { + return input.stream() + .map(RocksAddressBookStore::fromDTO) + .collect(ImmutableSet.toImmutableSet()); + } +} diff --git a/core/src/main/java/com/radixdlt/rev2/modules/AddressBookModule.java b/core/src/main/java/com/radixdlt/rev2/modules/AddressBookModule.java new file mode 100644 index 0000000000..de2365efd8 --- /dev/null +++ b/core/src/main/java/com/radixdlt/rev2/modules/AddressBookModule.java @@ -0,0 +1,127 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.rev2.modules; + +import com.google.common.annotations.VisibleForTesting; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.radixdlt.environment.NodeRustEnvironment; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.p2p.RocksDbAddressBookStore; +import com.radixdlt.p2p.RocksDbHighPriorityPeersStore; +import com.radixdlt.p2p.addressbook.AddressBookPersistence; +import com.radixdlt.p2p.addressbook.BerkeleyAddressBookStore; +import com.radixdlt.p2p.addressbook.RocksAddressBookStore; +import com.radixdlt.serialization.Serialization; +import com.radixdlt.store.BerkeleyDbDefaults; +import com.radixdlt.store.NodeStorageLocation; +import com.radixdlt.utils.properties.RuntimeProperties; + +public class AddressBookModule extends AbstractModule { + @Provides + @Singleton + AddressBookPersistence addressBookPersistence( + RuntimeProperties properties, + Serialization serialization, + Metrics metrics, + @NodeStorageLocation String nodeStorageLocation, + NodeRustEnvironment environment) { + + var addressBookStore = + new RocksAddressBookStore( + RocksDbAddressBookStore.create(metrics, environment), + RocksDbHighPriorityPeersStore.create(metrics, environment)); + + ensureMigrated(addressBookStore, properties, serialization, metrics, nodeStorageLocation); + + return addressBookStore; + } + + @VisibleForTesting + public static void ensureMigrated( + RocksAddressBookStore addressBookStore, + RuntimeProperties properties, + Serialization serialization, + Metrics metrics, + String nodeStorageLocation) { + if (addressBookStore.isMigrated()) { + return; + } + + var berkeleyAddressBookStore = + new BerkeleyAddressBookStore( + serialization, + metrics, + nodeStorageLocation, + BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties)); + + try (berkeleyAddressBookStore) { + berkeleyAddressBookStore.getAllEntries().forEach(addressBookStore::upsertEntry); + addressBookStore.storeHighPriorityPeers(berkeleyAddressBookStore.getHighPriorityPeers()); + addressBookStore.markAsMigrated(); + } + } +} diff --git a/core/src/main/java/com/radixdlt/rev2/modules/BerkeleySafetyStoreModule.java b/core/src/main/java/com/radixdlt/rev2/modules/PersistentSafetyStateStoreModule.java similarity index 76% rename from core/src/main/java/com/radixdlt/rev2/modules/BerkeleySafetyStoreModule.java rename to core/src/main/java/com/radixdlt/rev2/modules/PersistentSafetyStateStoreModule.java index fbedeeb34d..e4a6feabe4 100644 --- a/core/src/main/java/com/radixdlt/rev2/modules/BerkeleySafetyStoreModule.java +++ b/core/src/main/java/com/radixdlt/rev2/modules/PersistentSafetyStateStoreModule.java @@ -64,39 +64,57 @@ package com.radixdlt.rev2.modules; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; -import com.google.inject.multibindings.Multibinder; import com.radixdlt.consensus.safety.BerkeleySafetyStateStore; import com.radixdlt.consensus.safety.PersistentSafetyStateStore; -import com.radixdlt.environment.NodeAutoCloseable; +import com.radixdlt.consensus.safety.RocksSafetyStateStore; +import com.radixdlt.environment.NodeRustEnvironment; import com.radixdlt.monitoring.Metrics; +import com.radixdlt.safety.RocksDbSafetyStore; import com.radixdlt.serialization.Serialization; import com.radixdlt.store.BerkeleyDbDefaults; import com.radixdlt.store.NodeStorageLocation; import com.radixdlt.utils.properties.RuntimeProperties; -public class BerkeleySafetyStoreModule extends AbstractModule { - @Override - protected void configure() { - bind(PersistentSafetyStateStore.class).to(BerkeleySafetyStateStore.class); - Multibinder.newSetBinder(binder(), NodeAutoCloseable.class) - .addBinding() - .to(BerkeleySafetyStateStore.class); - } - +public class PersistentSafetyStateStoreModule extends AbstractModule { @Provides @Singleton - BerkeleySafetyStateStore safetyStateStore( + PersistentSafetyStateStore persistentSafetyStateStore( + RuntimeProperties properties, + Serialization serialization, + Metrics metrics, + @NodeStorageLocation String nodeStorageLocation, + NodeRustEnvironment environment) { + + var rocksSafetyStateStore = + new RocksSafetyStateStore(RocksDbSafetyStore.create(metrics, environment)); + + ensureMigrated(rocksSafetyStateStore, properties, serialization, metrics, nodeStorageLocation); + + return rocksSafetyStateStore; + } + + @VisibleForTesting + public static void ensureMigrated( + RocksSafetyStateStore rocksSafetyStateStore, RuntimeProperties properties, Serialization serialization, Metrics metrics, - @NodeStorageLocation String nodeStorageLocation) { - return new BerkeleySafetyStateStore( - serialization, - metrics, - nodeStorageLocation, - BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties)); + String nodeStorageLocation) { + if (!rocksSafetyStateStore.isMigrated()) { + var berkeleySafetyStateStore = + new BerkeleySafetyStateStore( + serialization, + metrics, + nodeStorageLocation, + BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties)); + try (berkeleySafetyStateStore) { + berkeleySafetyStateStore.get().ifPresent(rocksSafetyStateStore::commitState); + rocksSafetyStateStore.markAsMigrated(); + } + } } } diff --git a/core/src/main/java/com/radixdlt/rev2/modules/REv2StateManagerModule.java b/core/src/main/java/com/radixdlt/rev2/modules/REv2StateManagerModule.java index 9d85ff52c5..53d7f6f51d 100644 --- a/core/src/main/java/com/radixdlt/rev2/modules/REv2StateManagerModule.java +++ b/core/src/main/java/com/radixdlt/rev2/modules/REv2StateManagerModule.java @@ -101,7 +101,6 @@ import com.radixdlt.transactions.NotarizedTransactionHash; import com.radixdlt.transactions.PreparedNotarizedTransaction; import com.radixdlt.transactions.RawNotarizedTransaction; -import java.io.File; public final class REv2StateManagerModule extends AbstractModule { @@ -205,10 +204,10 @@ public void configure() { new AbstractModule() { @Provides @Singleton - DatabaseBackendConfig databaseBackendConfig( + @NodeStorageLocation + DatabaseBackendConfig stateManagerDatabaseBackendConfig( @NodeStorageLocation String nodeStorageLocation) { - return new DatabaseBackendConfig( - new File(nodeStorageLocation, "state_manager").getPath()); + return new DatabaseBackendConfig(nodeStorageLocation); } @Provides @@ -217,7 +216,7 @@ private NodeRustEnvironment stateManager( MempoolRelayDispatcher mempoolRelayDispatcher, FatalPanicHandler fatalPanicHandler, Network network, - DatabaseBackendConfig databaseBackendConfig, + @NodeStorageLocation DatabaseBackendConfig nodeDatabaseBackendConfig, DatabaseConfig databaseConfig) { return new NodeRustEnvironment( mempoolRelayDispatcher, @@ -226,7 +225,7 @@ private NodeRustEnvironment stateManager( NetworkDefinition.from(network), mempoolConfig, vertexLimitsConfigOpt, - databaseBackendConfig, + nodeDatabaseBackendConfig, databaseConfig, getLoggingConfig(), stateTreeGcConfig, diff --git a/core/src/main/java/com/radixdlt/store/NodeStorageLocationFromPropertiesModule.java b/core/src/main/java/com/radixdlt/store/StorageLocationFromPropertiesModule.java similarity index 98% rename from core/src/main/java/com/radixdlt/store/NodeStorageLocationFromPropertiesModule.java rename to core/src/main/java/com/radixdlt/store/StorageLocationFromPropertiesModule.java index c42726ec35..e24d33893b 100644 --- a/core/src/main/java/com/radixdlt/store/NodeStorageLocationFromPropertiesModule.java +++ b/core/src/main/java/com/radixdlt/store/StorageLocationFromPropertiesModule.java @@ -70,7 +70,7 @@ import com.radixdlt.utils.properties.RuntimeProperties; /** Reads node's storage location from properties */ -public final class NodeStorageLocationFromPropertiesModule extends AbstractModule { +public final class StorageLocationFromPropertiesModule extends AbstractModule { @Provides @Singleton @NodeStorageLocation diff --git a/core/src/main/resources/default.config b/core/src/main/resources/default.config index 1f3350a483..ea0d8249e4 100755 --- a/core/src/main/resources/default.config +++ b/core/src/main/resources/default.config @@ -143,7 +143,6 @@ cp.port=8080 # Default: ./RADIXDB # db.location=./RADIXDB - #### ## Debug configuration #### diff --git a/core/src/test-core/java/com/radixdlt/modules/FunctionalRadixNodeModule.java b/core/src/test-core/java/com/radixdlt/modules/FunctionalRadixNodeModule.java index 05c2ff8929..4aa500a38e 100644 --- a/core/src/test-core/java/com/radixdlt/modules/FunctionalRadixNodeModule.java +++ b/core/src/test-core/java/com/radixdlt/modules/FunctionalRadixNodeModule.java @@ -73,10 +73,7 @@ import com.radixdlt.consensus.epoch.EpochsConsensusModule; import com.radixdlt.consensus.liveness.ProposalGenerator; import com.radixdlt.consensus.sync.BFTSyncPatienceMillis; -import com.radixdlt.environment.NoEpochsConsensusModule; -import com.radixdlt.environment.NoEpochsSyncModule; -import com.radixdlt.environment.NodeAutoCloseable; -import com.radixdlt.environment.ScenariosExecutionConfig; +import com.radixdlt.environment.*; import com.radixdlt.genesis.RawGenesisDataWithHash; import com.radixdlt.lang.Option; import com.radixdlt.ledger.MockedLedgerModule; @@ -123,7 +120,7 @@ static NodeStorageConfig file(File folder) { public enum SafetyRecoveryConfig { MOCKED, - BERKELEY_DB, + REAL, } public static final class ConsensusConfig { @@ -316,7 +313,7 @@ public void configure() { switch (this.safetyRecoveryConfig) { case MOCKED -> install(new MockedSafetyStoreModule()); - case BERKELEY_DB -> install(new BerkeleySafetyStoreModule()); + case REAL -> install(new PersistentSafetyStateStoreModule()); } // Consensus diff --git a/core/src/test-core/java/com/radixdlt/rev2/NodeRustEnvironmentHelper.java b/core/src/test-core/java/com/radixdlt/rev2/NodeRustEnvironmentHelper.java new file mode 100644 index 0000000000..5b9a73ad9f --- /dev/null +++ b/core/src/test-core/java/com/radixdlt/rev2/NodeRustEnvironmentHelper.java @@ -0,0 +1,104 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.rev2; + +import com.radixdlt.environment.*; +import com.radixdlt.lang.Option; +import com.radixdlt.mempool.RustMempoolConfig; +import com.radixdlt.protocol.ProtocolConfig; +import com.radixdlt.transaction.LedgerSyncLimitsConfig; + +public class NodeRustEnvironmentHelper { + public static NodeRustEnvironment createNodeRustEnvironment(String dbPath) { + final var mempoolMaxTotalTransactionsSize = 10 * 1024 * 1024; + final var mempoolMaxTransactionCount = 20; + final var stateManagerDbConfig = new DatabaseBackendConfig(dbPath); + + final var config = + new StateManagerConfig( + NetworkDefinition.INT_TEST_NET, + Option.some( + new RustMempoolConfig(mempoolMaxTotalTransactionsSize, mempoolMaxTransactionCount)), + Option.none(), + stateManagerDbConfig, + new DatabaseConfig(false, false, false, false), + LoggingConfig.getDefault(), + StateTreeGcConfig.forTesting(), + LedgerProofsGcConfig.forTesting(), + LedgerSyncLimitsConfig.defaults(), + ProtocolConfig.testingDefault(), + false, + ScenariosExecutionConfig.NONE); + + return new NodeRustEnvironment( + tx -> {}, // A no-op dispatcher of transactions to be relayed. + () -> {}, // A no-op fatal panic handler. Please note that a JNI-invoking test (like this + // one) will observe + // panics as runtime exceptions propagated up the stack (through JNI), which will fail the + // test + // gracefully anyway. + config); + } +} diff --git a/core/src/test/java/com/radixdlt/consensus/safety/RocksSafetyStateStoreTest.java b/core/src/test/java/com/radixdlt/consensus/safety/RocksSafetyStateStoreTest.java new file mode 100644 index 0000000000..e3f01b54d6 --- /dev/null +++ b/core/src/test/java/com/radixdlt/consensus/safety/RocksSafetyStateStoreTest.java @@ -0,0 +1,122 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.consensus.safety; + +import static org.junit.Assert.*; + +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.monitoring.MetricsInitializer; +import com.radixdlt.rev2.NodeRustEnvironmentHelper; +import com.radixdlt.safety.RocksDbSafetyStore; +import com.radixdlt.utils.SerializerTestDataGenerator; +import java.io.IOException; +import java.util.Optional; +import java.util.function.Consumer; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class RocksSafetyStateStoreTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void test_safety_state_can_be_saved_and_restored() { + runTest( + safetyStore -> { + // Fresh store is empty + assertTrue(safetyStore.get().isEmpty()); + + // Save a safety state + var safetyState = createSafetyState(); + safetyStore.commitState(safetyState); + + // Retrieve the saved safety state + var restoredSafetyState = safetyStore.get(); + assertTrue(restoredSafetyState.isPresent()); + assertEquals(safetyState, restoredSafetyState.get()); + }); + } + + private static SafetyState createSafetyState() { + var vote = SerializerTestDataGenerator.randomVote(); + return SafetyState.create(vote.getAuthor(), vote.getRound(), Optional.of(vote)); + } + + private void runTest(Consumer test) { + try (var environment = + NodeRustEnvironmentHelper.createNodeRustEnvironment(folder.newFolder().getPath())) { + var safetyStore = RocksDbSafetyStore.create(newMetrics(), environment); + try (var underTest = new RocksSafetyStateStore(safetyStore)) { + test.accept(underTest); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static Metrics newMetrics() { + return new MetricsInitializer().initialize(); + } +} diff --git a/core/src/test/java/com/radixdlt/consensus/safety/SafetyStoreMigrationTest.java b/core/src/test/java/com/radixdlt/consensus/safety/SafetyStoreMigrationTest.java new file mode 100644 index 0000000000..9244907dad --- /dev/null +++ b/core/src/test/java/com/radixdlt/consensus/safety/SafetyStoreMigrationTest.java @@ -0,0 +1,146 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.consensus.safety; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.radixdlt.consensus.bft.BFTValidatorId; +import com.radixdlt.environment.NodeRustEnvironment; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.monitoring.MetricsInitializer; +import com.radixdlt.rev2.NodeRustEnvironmentHelper; +import com.radixdlt.rev2.modules.PersistentSafetyStateStoreModule; +import com.radixdlt.safety.RocksDbSafetyStore; +import com.radixdlt.serialization.Serialization; +import com.radixdlt.serialization.core.ClasspathScanningSerializationPolicy; +import com.radixdlt.serialization.core.ClasspathScanningSerializerIds; +import com.radixdlt.store.BerkeleyDbDefaults; +import com.radixdlt.utils.properties.RuntimeProperties; +import java.io.IOException; +import java.util.Map; +import org.apache.commons.cli.ParseException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class SafetyStoreMigrationTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + record TestEnvironment( + String nodeStorageLocation, + NodeRustEnvironment nodeRustEnvironment, + Metrics metrics, + Serialization serialization, + RuntimeProperties properties) { + public RocksSafetyStateStore rocksSafetyStateStore() { + return new RocksSafetyStateStore(RocksDbSafetyStore.create(metrics, nodeRustEnvironment)); + } + + public BerkeleySafetyStateStore berkeleySafetyStateStore() { + return new BerkeleySafetyStateStore( + serialization, + metrics, + nodeStorageLocation, + BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties)); + } + } + + private TestEnvironment createTestEnvironment() throws IOException, ParseException { + return new TestEnvironment( + folder.getRoot().getPath(), + NodeRustEnvironmentHelper.createNodeRustEnvironment(folder.newFolder().getPath()), + new MetricsInitializer().initialize(), + Serialization.create( + ClasspathScanningSerializerIds.create(), ClasspathScanningSerializationPolicy.create()), + RuntimeProperties.defaultWithOverrides(Map.of())); + } + + @Test + public void safety_store_migrates_successfully() throws IOException, ParseException { + var injector = createTestEnvironment(); + var safetyState = SafetyState.initialState(BFTValidatorId.random()); + + // Create some entries in the Berkeley safety store + try (var berkeleySafetyStateStore = injector.berkeleySafetyStateStore()) { + berkeleySafetyStateStore.commitState(safetyState); + } + + // Perform the migration and check content + try (var safetyStateStore = injector.rocksSafetyStateStore()) { + PersistentSafetyStateStoreModule.ensureMigrated( + safetyStateStore, + injector.properties, + injector.serialization, + injector.metrics, + injector.nodeStorageLocation); + + var storedState = safetyStateStore.get(); + + assertTrue(storedState.isPresent()); + assertEquals(safetyState, storedState.get()); + } + } +} diff --git a/core/src/test/java/com/radixdlt/p2p/addressbook/AddressBookMigrationTest.java b/core/src/test/java/com/radixdlt/p2p/addressbook/AddressBookMigrationTest.java new file mode 100644 index 0000000000..4811d19ac8 --- /dev/null +++ b/core/src/test/java/com/radixdlt/p2p/addressbook/AddressBookMigrationTest.java @@ -0,0 +1,168 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p.addressbook; + +import static com.radixdlt.p2p.addressbook.RocksAddressBookStoreTest.*; +import static org.junit.Assert.assertEquals; + +import com.radixdlt.environment.NodeRustEnvironment; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.monitoring.MetricsInitializer; +import com.radixdlt.p2p.RocksDbAddressBookStore; +import com.radixdlt.p2p.RocksDbHighPriorityPeersStore; +import com.radixdlt.rev2.NodeRustEnvironmentHelper; +import com.radixdlt.rev2.modules.AddressBookModule; +import com.radixdlt.serialization.Serialization; +import com.radixdlt.serialization.core.ClasspathScanningSerializationPolicy; +import com.radixdlt.serialization.core.ClasspathScanningSerializerIds; +import com.radixdlt.store.BerkeleyDbDefaults; +import com.radixdlt.utils.properties.RuntimeProperties; +import java.io.IOException; +import java.util.*; +import org.apache.commons.cli.ParseException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class AddressBookMigrationTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + record TestEnvironment( + String nodeStorageLocation, + NodeRustEnvironment nodeRustEnvironment, + Metrics metrics, + Serialization serialization, + RuntimeProperties properties) { + public RocksAddressBookStore rocksAddressBookPersistence() { + return new RocksAddressBookStore( + RocksDbAddressBookStore.create(metrics, nodeRustEnvironment), + RocksDbHighPriorityPeersStore.create(metrics, nodeRustEnvironment)); + } + + public BerkeleyAddressBookStore berkeleyAddressBookPersistence() { + return new BerkeleyAddressBookStore( + serialization, + metrics, + nodeStorageLocation, + BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties)); + } + } + + private TestEnvironment createTestEnvironment() throws IOException, ParseException { + return new TestEnvironment( + folder.getRoot().getPath(), + NodeRustEnvironmentHelper.createNodeRustEnvironment(folder.newFolder().getPath()), + new MetricsInitializer().initialize(), + Serialization.create( + ClasspathScanningSerializerIds.create(), ClasspathScanningSerializationPolicy.create()), + RuntimeProperties.defaultWithOverrides(Map.of())); + } + + @Test + public void address_book_migrates_successfully() throws IOException, ParseException { + var environment = createTestEnvironment(); + var addresses = Set.of(newAddressBookEntry(1), newAddressBookEntry(2), newAddressBookEntry(3)); + + // Create some entries in the Berkeley address book + try (var berkeleyAddressBook = environment.berkeleyAddressBookPersistence()) { + addresses.forEach(berkeleyAddressBook::upsertEntry); + } + + // Perform the migration and check content + try (var addressBook = environment.rocksAddressBookPersistence()) { + AddressBookModule.ensureMigrated( + addressBook, + environment.properties, + environment.serialization, + environment.metrics, + environment.nodeStorageLocation); + + assertEquals(new HashSet<>(addressBook.getAllEntries()), addresses); + } + } + + @Test + public void high_priority_peers_migrate_successfully() throws IOException, ParseException { + var environment = createTestEnvironment(); + var highPriorityPeers = List.of(newNodeId(21), newNodeId(32), newNodeId(43)); + + // Create some entries in the Berkeley address book + try (var berkeleyAddressBook = environment.berkeleyAddressBookPersistence()) { + berkeleyAddressBook.storeHighPriorityPeers(highPriorityPeers); + } + + // Perform the migration and check content + try (var addressBook = environment.rocksAddressBookPersistence()) { + AddressBookModule.ensureMigrated( + addressBook, + environment.properties, + environment.serialization, + environment.metrics, + environment.nodeStorageLocation); + + assertEquals(highPriorityPeers, addressBook.getHighPriorityPeers()); + } + } +} diff --git a/core/src/test/java/com/radixdlt/p2p/addressbook/RocksAddressBookStoreTest.java b/core/src/test/java/com/radixdlt/p2p/addressbook/RocksAddressBookStoreTest.java new file mode 100644 index 0000000000..b28c5cdcbf --- /dev/null +++ b/core/src/test/java/com/radixdlt/p2p/addressbook/RocksAddressBookStoreTest.java @@ -0,0 +1,220 @@ +/* Copyright 2021 Radix Publishing Ltd incorporated in Jersey (Channel Islands). + * + * Licensed under the Radix License, Version 1.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at: + * + * radixfoundation.org/licenses/LICENSE-v1 + * + * The Licensor hereby grants permission for the Canonical version of the Work to be + * published, distributed and used under or by reference to the Licensor’s trademark + * Radix ® and use of any unregistered trade names, logos or get-up. + * + * The Licensor provides the Work (and each Contributor provides its Contributions) on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + * + * Whilst the Work is capable of being deployed, used and adopted (instantiated) to create + * a distributed ledger it is your responsibility to test and validate the code, together + * with all logic and performance of that code under all foreseeable scenarios. + * + * The Licensor does not make or purport to make and hereby excludes liability for all + * and any representation, warranty or undertaking in any form whatsoever, whether express + * or implied, to any entity or person, including any representation, warranty or + * undertaking, as to the functionality security use, value or other characteristics of + * any distributed ledger nor in respect the functioning or value of any tokens which may + * be created stored or transferred using the Work. The Licensor does not warrant that the + * Work or any use of the Work complies with any law or regulation in any territory where + * it may be implemented or used or that it will be appropriate for any specific purpose. + * + * Neither the licensor nor any current or former employees, officers, directors, partners, + * trustees, representatives, agents, advisors, contractors, or volunteers of the Licensor + * shall be liable for any direct or indirect, special, incidental, consequential or other + * losses of any kind, in tort, contract or otherwise (including but not limited to loss + * of revenue, income or profits, or loss of use or data, or loss of reputation, or loss + * of any economic or other opportunity of whatsoever nature or howsoever arising), arising + * out of or in connection with (without limitation of any use, misuse, of any ledger system + * or use made or its functionality or any performance or operation of any code or protocol + * caused by bugs or programming or logic errors or otherwise); + * + * A. any offer, purchase, holding, use, sale, exchange or transmission of any + * cryptographic keys, tokens or assets created, exchanged, stored or arising from any + * interaction with the Work; + * + * B. any failure in a transmission or loss of any token or assets keys or other digital + * artefacts due to errors in transmission; + * + * C. bugs, hacks, logic errors or faults in the Work or any communication; + * + * D. system software or apparatus including but not limited to losses caused by errors + * in holding or transmitting tokens by any third-party; + * + * E. breaches or failure of security including hacker attacks, loss or disclosure of + * password, loss of private key, unauthorised use or misuse of such passwords or keys; + * + * F. any losses including loss of anticipated savings or other benefits resulting from + * use of the Work or any changes to the Work (however implemented). + * + * You are solely responsible for; testing, validating and evaluation of all operation + * logic, functionality, security and appropriateness of using the Work for any commercial + * or non-commercial purpose and for any reproduction or redistribution by You of the + * Work. You assume all risks associated with Your use of the Work and the exercise of + * permissions under this License. + */ + +package com.radixdlt.p2p.addressbook; + +import static org.junit.Assert.*; + +import com.google.common.collect.ImmutableSet; +import com.radixdlt.crypto.ECDSASecp256k1PublicKey; +import com.radixdlt.crypto.ECKeyPair; +import com.radixdlt.monitoring.Metrics; +import com.radixdlt.monitoring.MetricsInitializer; +import com.radixdlt.p2p.*; +import com.radixdlt.p2p.addressbook.AddressBookEntry.PeerAddressEntry; +import com.radixdlt.p2p.addressbook.AddressBookEntry.PeerAddressEntry.FailedHandshake; +import com.radixdlt.p2p.addressbook.AddressBookEntry.PeerAddressEntry.LatestConnectionStatus; +import com.radixdlt.rev2.NodeRustEnvironmentHelper; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.Random; +import java.util.function.Consumer; +import java.util.stream.IntStream; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class RocksAddressBookStoreTest { + @Rule public TemporaryFolder folder = new TemporaryFolder(); + + private static final Random RANDOM = new Random(); + + @Test + public void test_address_book_entries_can_be_saved_and_restored() { + runTest( + rocksAddressBookStore -> { + // New store is empty + var empty = rocksAddressBookStore.getAllEntries(); + assertTrue(empty.isEmpty()); + + // One entry can be stored and restored + var entry1 = newAddressBookEntry(1); + assertTrue(rocksAddressBookStore.upsertEntry(entry1)); + + var allEntries = rocksAddressBookStore.getAllEntries(); + assertEquals(1L, allEntries.size()); + assertEquals(entry1, allEntries.get(0)); + + // Another entry can be stored and restored + var entry2 = newAddressBookEntry(2); + assertTrue(rocksAddressBookStore.upsertEntry(entry2)); + + allEntries = rocksAddressBookStore.getAllEntries(); + assertEquals(2L, allEntries.size()); + assertEquals(entry1, allEntries.get(0)); + assertEquals(entry2, allEntries.get(1)); + + // An entry can be deleted + assertTrue(rocksAddressBookStore.removeEntry(entry1.getNodeId())); + + allEntries = rocksAddressBookStore.getAllEntries(); + assertEquals(1L, allEntries.size()); + assertEquals(entry2, allEntries.get(0)); + + // Address book can be reset + rocksAddressBookStore.reset(); + + empty = rocksAddressBookStore.getAllEntries(); + assertTrue(empty.isEmpty()); + }); + } + + @Test + public void test_high_priority_peers_can_be_saved_and_restored() { + runTest( + rocksAddressBookStore -> { + var peers = List.of(newNodeId(11), newNodeId(12), newNodeId(13)); + + // New store is empty + var empty = rocksAddressBookStore.getHighPriorityPeers(); + assertTrue(empty.isEmpty()); + + // Peers can be stored and restored + rocksAddressBookStore.storeHighPriorityPeers(peers); + + var allPeers = rocksAddressBookStore.getHighPriorityPeers(); + + assertEquals(3L, allPeers.size()); + assertEquals(peers, allPeers); + }); + } + + private void runTest(Consumer test) { + try (var environment = + NodeRustEnvironmentHelper.createNodeRustEnvironment(folder.newFolder().getPath())) { + var addressBook = RocksDbAddressBookStore.create(newMetrics(), environment); + var peersStore = RocksDbHighPriorityPeersStore.create(newMetrics(), environment); + try (var underTest = new RocksAddressBookStore(addressBook, peersStore)) { + test.accept(underTest); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static Metrics newMetrics() { + return new MetricsInitializer().initialize(); + } + + public static AddressBookEntry newAddressBookEntry(int id) { + var pubKey = newPubKey((byte) id); + var bannedUntil = newBannedUntil(); + + return new AddressBookEntry( + NodeId.fromPublicKey(pubKey), bannedUntil, newKnownAddresses(pubKey)); + } + + public static NodeId newNodeId(int id) { + return NodeId.fromPublicKey(newPubKey((byte) id)); + } + + private static ECDSASecp256k1PublicKey newPubKey(byte id) { + return ECKeyPair.fromSeed(new byte[] {id}).getPublicKey(); + } + + private static ImmutableSet newKnownAddresses(ECDSASecp256k1PublicKey pubKey) { + return IntStream.range(0, RANDOM.nextInt(3)) + .mapToObj(__ -> newPeerAddressEntry(pubKey)) + .collect(ImmutableSet.toImmutableSet()); + } + + private static PeerAddressEntry newPeerAddressEntry(ECDSASecp256k1PublicKey pubKey) { + var failedHandshake = newFailedHandshake(); + var latestConnectionStatus = newLatestConnectionStatus(); + var uri = RadixNodeUri.fromPubKeyAndAddress(1, pubKey, "127.0.0.1", 30000); + + return new PeerAddressEntry(uri, latestConnectionStatus, failedHandshake); + } + + private static Optional newLatestConnectionStatus() { + return RANDOM.nextBoolean() + ? Optional.of( + RANDOM.nextBoolean() ? LatestConnectionStatus.FAILURE : LatestConnectionStatus.SUCCESS) + : Optional.empty(); + } + + private static Optional newBannedUntil() { + return RANDOM.nextBoolean() + ? Optional.of(Instant.ofEpochMilli(Math.abs(RANDOM.nextLong()))) + : Optional.empty(); + } + + private static Optional newFailedHandshake() { + return RANDOM.nextBoolean() + ? Optional.of(new FailedHandshake(Instant.ofEpochMilli(Math.abs(RANDOM.nextLong())))) + : Optional.empty(); + } +} diff --git a/core/src/test/java/com/radixdlt/p2p/test/P2PTestNetworkRunner.java b/core/src/test/java/com/radixdlt/p2p/test/P2PTestNetworkRunner.java index b7ebd6a73c..9d6f95860f 100644 --- a/core/src/test/java/com/radixdlt/p2p/test/P2PTestNetworkRunner.java +++ b/core/src/test/java/com/radixdlt/p2p/test/P2PTestNetworkRunner.java @@ -74,10 +74,13 @@ import com.radixdlt.consensus.bft.BFTValidatorId; import com.radixdlt.consensus.bft.Round; import com.radixdlt.consensus.bft.Self; +import com.radixdlt.consensus.safety.BerkeleySafetyStateStore; +import com.radixdlt.consensus.safety.PersistentSafetyStateStore; import com.radixdlt.crypto.ECDSASecp256k1PublicKey; import com.radixdlt.crypto.ECKeyOps; import com.radixdlt.crypto.ECKeyPair; import com.radixdlt.environment.Environment; +import com.radixdlt.environment.NodeAutoCloseable; import com.radixdlt.environment.StartProcessorOnRunner; import com.radixdlt.environment.deterministic.DeterministicProcessor; import com.radixdlt.environment.deterministic.network.ControlledDispatcher; @@ -94,6 +97,7 @@ import com.radixdlt.p2p.*; import com.radixdlt.p2p.addressbook.AddressBook; import com.radixdlt.p2p.addressbook.AddressBookPersistence; +import com.radixdlt.p2p.addressbook.BerkeleyAddressBookStore; import com.radixdlt.p2p.capability.Capabilities; import com.radixdlt.p2p.transport.PeerOutboundBootstrap; import com.radixdlt.protocol.NewestProtocolVersion; @@ -101,7 +105,9 @@ import com.radixdlt.serialization.DefaultSerialization; import com.radixdlt.serialization.Serialization; import com.radixdlt.statecomputer.ProtocolState; +import com.radixdlt.store.BerkeleyDbDefaults; import com.radixdlt.utils.properties.RuntimeProperties; +import com.sleepycat.je.EnvironmentConfig; import java.io.IOException; import java.util.Objects; import java.util.function.Function; @@ -188,6 +194,27 @@ private static Injector createInjector( throws ParseException { final var properties = RuntimeProperties.fromCommandLineArgs(new String[] {}); return Guice.createInjector( + new AbstractModule() { + + // FIXME: Replacing implementation with the RocksDB version does not work out of the box + // because NodeRustEnvironment can't + // be properly instantiated (error on Rust side). + @Override + protected void configure() { + bind(AddressBookPersistence.class).to(BerkeleyAddressBookStore.class); + bind(PersistentSafetyStateStore.class).to(BerkeleySafetyStateStore.class); + + var binder = Multibinder.newSetBinder(binder(), NodeAutoCloseable.class); + binder.addBinding().to(PersistentSafetyStateStore.class); + binder.addBinding().to(AddressBookPersistence.class); + } + + @Provides + @Singleton + EnvironmentConfig environmentConfig(RuntimeProperties properties) { + return BerkeleyDbDefaults.createDefaultEnvConfigFromProperties(properties); + } + }, Modules.override(new P2PModule(properties)) .with( new AbstractModule() { @@ -265,10 +292,7 @@ protected void configure() { } public void cleanup() { - this.nodes.forEach( - node -> { - node.injector.getInstance(AddressBookPersistence.class).close(); - }); + this.nodes.forEach(node -> node.injector.getInstance(AddressBookPersistence.class).close()); } public RadixNodeUri getUri(int nodeIndex) { diff --git a/core/src/test/java/com/radixdlt/recovery/REv2ConsensusLedgerRecoveryTest.java b/core/src/test/java/com/radixdlt/recovery/REv2ConsensusLedgerRecoveryTest.java index 36f3f519fd..ada9a3ccfd 100644 --- a/core/src/test/java/com/radixdlt/recovery/REv2ConsensusLedgerRecoveryTest.java +++ b/core/src/test/java/com/radixdlt/recovery/REv2ConsensusLedgerRecoveryTest.java @@ -101,7 +101,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), false, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/recovery/REv2LedgerRecoveryTest.java b/core/src/test/java/com/radixdlt/recovery/REv2LedgerRecoveryTest.java index f1ff659d89..0d6c9eeac3 100644 --- a/core/src/test/java/com/radixdlt/recovery/REv2LedgerRecoveryTest.java +++ b/core/src/test/java/com/radixdlt/recovery/REv2LedgerRecoveryTest.java @@ -119,7 +119,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), false, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/REv2IncreasingEpochTest.java b/core/src/test/java/com/radixdlt/rev2/REv2IncreasingEpochTest.java index 1f6cbb59d0..d60da7b6eb 100644 --- a/core/src/test/java/com/radixdlt/rev2/REv2IncreasingEpochTest.java +++ b/core/src/test/java/com/radixdlt/rev2/REv2IncreasingEpochTest.java @@ -93,7 +93,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), true, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/REv2LargeTransactionTest.java b/core/src/test/java/com/radixdlt/rev2/REv2LargeTransactionTest.java index cbc83068cb..3fade12bc3 100644 --- a/core/src/test/java/com/radixdlt/rev2/REv2LargeTransactionTest.java +++ b/core/src/test/java/com/radixdlt/rev2/REv2LargeTransactionTest.java @@ -105,7 +105,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), false, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerWithSyncRelay( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/REv2RegisterValidatorTest.java b/core/src/test/java/com/radixdlt/rev2/REv2RegisterValidatorTest.java index 77c58628a1..1483205151 100644 --- a/core/src/test/java/com/radixdlt/rev2/REv2RegisterValidatorTest.java +++ b/core/src/test/java/com/radixdlt/rev2/REv2RegisterValidatorTest.java @@ -142,7 +142,7 @@ private DeterministicTest createTest() { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), true, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/REv2RejectMultipleIntentsTest.java b/core/src/test/java/com/radixdlt/rev2/REv2RejectMultipleIntentsTest.java index d32f6e6420..73a566e8ca 100644 --- a/core/src/test/java/com/radixdlt/rev2/REv2RejectMultipleIntentsTest.java +++ b/core/src/test/java/com/radixdlt/rev2/REv2RejectMultipleIntentsTest.java @@ -104,7 +104,7 @@ private DeterministicTest createTest(ProposalGenerator proposalGenerator) { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), false, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionMempoolTest.java b/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionMempoolTest.java index 89f4fe37c9..f8dfe44f47 100644 --- a/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionMempoolTest.java +++ b/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionMempoolTest.java @@ -122,7 +122,7 @@ private DeterministicTest createTest(RustMempoolConfig mempoolConfig) { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), this.epochs, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionTest.java b/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionTest.java index 95c27f7757..941a3f38e3 100644 --- a/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionTest.java +++ b/core/src/test/java/com/radixdlt/rev2/REv2RejectedTransactionTest.java @@ -119,7 +119,7 @@ private DeterministicTest createTest(ProposalGenerator proposalGenerator) { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), epochs, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(1000), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/RustMempoolTest.java b/core/src/test/java/com/radixdlt/rev2/RustMempoolTest.java index 099e50e1ec..28329b210b 100644 --- a/core/src/test/java/com/radixdlt/rev2/RustMempoolTest.java +++ b/core/src/test/java/com/radixdlt/rev2/RustMempoolTest.java @@ -80,7 +80,7 @@ import com.radixdlt.transaction.LedgerSyncLimitsConfig; import com.radixdlt.transaction.REv2TransactionAndProofStore; import com.radixdlt.transactions.PreparedNotarizedTransaction; -import com.radixdlt.transactions.RawNotarizedTransaction; +import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -91,59 +91,14 @@ public final class RustMempoolTest { - private static final DatabaseConfig TEST_DATABASE_CONFIG = - new DatabaseConfig(false, false, false, false); - @Rule public TemporaryFolder folder = new TemporaryFolder(); - /** A no-op dispatcher of transactions to be relayed. */ - private static final MempoolRelayDispatcher NOOP_DISPATCHER = tx -> {}; - - /** - * A no-op fatal panic handler. Please note that a JNI-invoking test (like this one) will observe - * panics as runtime exceptions propagated up the stack (through JNI), which will fail the test - * gracefully anyway. - */ - private static final FatalPanicHandler NOOP_HANDLER = () -> {}; - - private static void initStateComputer(NodeRustEnvironment nodeRustEnvironment) { - final var metrics = new MetricsInitializer().initialize(); - final var genesisProvider = - RawGenesisDataWithHash.fromGenesisData(GenesisData.testingDefaultEmpty()); - new REv2LedgerInitializer( - new Blake2b256Hasher(DefaultSerialization.getInstance()), - new RustStateComputer(metrics, nodeRustEnvironment), - new REv2TransactionsAndProofReader( - new REv2TransactionAndProofStore(metrics, nodeRustEnvironment), - LedgerSyncLimitsConfig.defaults(), - metrics)) - .initialize(genesisProvider); - } - @Test public void test_rust_mempool_add() throws Exception { - final var mempoolMaxTotalTransactionsSize = 10 * 1024 * 1024; - final var mempoolMaxTransactionCount = 20; - final var config = - new StateManagerConfig( - NetworkDefinition.INT_TEST_NET, - Option.some( - new RustMempoolConfig(mempoolMaxTotalTransactionsSize, mempoolMaxTransactionCount)), - Option.none(), - new DatabaseBackendConfig(folder.newFolder().getPath()), - TEST_DATABASE_CONFIG, - LoggingConfig.getDefault(), - StateTreeGcConfig.forTesting(), - LedgerProofsGcConfig.forTesting(), - LedgerSyncLimitsConfig.defaults(), - ProtocolConfig.testingDefault(), - false, - ScenariosExecutionConfig.NONE); - final var metrics = new MetricsInitializer().initialize(); - - try (var stateManager = new NodeRustEnvironment(NOOP_DISPATCHER, NOOP_HANDLER, config)) { - initStateComputer(stateManager); - final var rustMempool = new RustMempool(metrics, stateManager); + try (var nodeRustEnvironment = createNodeRustEnvironment()) { + initStateComputer(nodeRustEnvironment); + final var rustMempool = + new RustMempool(new MetricsInitializer().initialize(), nodeRustEnvironment); final var transaction1 = constructValidTransaction(0, 0); final var transaction2 = constructValidTransaction(0, 1); @@ -181,28 +136,10 @@ public void test_rust_mempool_add() throws Exception { @Test public void test_rust_mempool_getTxns() throws Exception { - final var mempoolMaxTotalTransactionsSize = 10 * 1024 * 1024; - final var mempoolMaxTransactionCount = 20; - final var config = - new StateManagerConfig( - NetworkDefinition.INT_TEST_NET, - Option.some( - new RustMempoolConfig(mempoolMaxTotalTransactionsSize, mempoolMaxTransactionCount)), - Option.none(), - new DatabaseBackendConfig(folder.newFolder().getPath()), - TEST_DATABASE_CONFIG, - LoggingConfig.getDefault(), - StateTreeGcConfig.forTesting(), - LedgerProofsGcConfig.forTesting(), - LedgerSyncLimitsConfig.defaults(), - ProtocolConfig.testingDefault(), - false, - ScenariosExecutionConfig.NONE); - final var metrics = new MetricsInitializer().initialize(); - - try (var stateManager = new NodeRustEnvironment(NOOP_DISPATCHER, NOOP_HANDLER, config)) { - initStateComputer(stateManager); - final var rustMempool = new RustMempool(metrics, stateManager); + try (var nodeRustEnvironment = createNodeRustEnvironment()) { + initStateComputer(nodeRustEnvironment); + final var rustMempool = + new RustMempool(new MetricsInitializer().initialize(), nodeRustEnvironment); final var transaction1 = constructValidTransaction(0, 0); final var transaction2 = constructValidTransaction(0, 1); final var transaction3 = constructValidTransaction(0, 2); @@ -323,28 +260,10 @@ public void test_rust_mempool_getTxns() throws Exception { @Test public void test_rust_mempool_getRelayTxns() throws Exception { - final var mempoolMaxTotalTransactionsSize = 10 * 1024 * 1024; - final var mempoolMaxTransactionCount = 20; - final var config = - new StateManagerConfig( - NetworkDefinition.INT_TEST_NET, - Option.some( - new RustMempoolConfig(mempoolMaxTotalTransactionsSize, mempoolMaxTransactionCount)), - Option.none(), - new DatabaseBackendConfig(folder.newFolder().getPath()), - TEST_DATABASE_CONFIG, - LoggingConfig.getDefault(), - StateTreeGcConfig.forTesting(), - LedgerProofsGcConfig.forTesting(), - LedgerSyncLimitsConfig.defaults(), - ProtocolConfig.testingDefault(), - false, - ScenariosExecutionConfig.NONE); - final var metrics = new MetricsInitializer().initialize(); - - try (var stateManager = new NodeRustEnvironment(NOOP_DISPATCHER, NOOP_HANDLER, config)) { - initStateComputer(stateManager); - final var rustMempool = new RustMempool(metrics, stateManager); + try (var nodeRustEnvironment = createNodeRustEnvironment()) { + initStateComputer(nodeRustEnvironment); + final var rustMempool = + new RustMempool(new MetricsInitializer().initialize(), nodeRustEnvironment); final var transaction1 = constructValidTransaction(0, 0); final var transaction2 = constructValidTransaction(0, 1); final var transaction3 = constructValidTransaction(0, 2); @@ -383,6 +302,51 @@ public void test_rust_mempool_getRelayTxns() throws Exception { } } + private NodeRustEnvironment createNodeRustEnvironment() throws IOException { + final var mempoolMaxTotalTransactionsSize = 10 * 1024 * 1024; + final var mempoolMaxTransactionCount = 20; + final var stateManagerDbConfig = new DatabaseBackendConfig(folder.newFolder().getPath()); + + final var config = + new StateManagerConfig( + NetworkDefinition.INT_TEST_NET, + Option.some( + new RustMempoolConfig(mempoolMaxTotalTransactionsSize, mempoolMaxTransactionCount)), + Option.none(), + stateManagerDbConfig, + new DatabaseConfig(false, false, false, false), + LoggingConfig.getDefault(), + StateTreeGcConfig.forTesting(), + LedgerProofsGcConfig.forTesting(), + LedgerSyncLimitsConfig.defaults(), + ProtocolConfig.testingDefault(), + false, + ScenariosExecutionConfig.NONE); + + return new NodeRustEnvironment( + tx -> {}, // A no-op dispatcher of transactions to be relayed. + () -> {}, // A no-op fatal panic handler. Please note that a JNI-invoking test (like this + // one) will observe + // panics as runtime exceptions propagated up the stack (through JNI), which will fail the + // test + // gracefully anyway. + config); + } + + private static void initStateComputer(NodeRustEnvironment nodeRustEnvironment) { + final var metrics = new MetricsInitializer().initialize(); + final var genesisProvider = + RawGenesisDataWithHash.fromGenesisData(GenesisData.testingDefaultEmpty()); + new REv2LedgerInitializer( + new Blake2b256Hasher(DefaultSerialization.getInstance()), + new RustStateComputer(metrics, nodeRustEnvironment), + new REv2TransactionsAndProofReader( + new REv2TransactionAndProofStore(metrics, nodeRustEnvironment), + LedgerSyncLimitsConfig.defaults(), + metrics)) + .initialize(genesisProvider); + } + private static PreparedNotarizedTransaction constructValidTransaction(long fromEpoch, int nonce) { return TransactionBuilder.forTests().fromEpoch(fromEpoch).nonce(nonce).prepare(); } diff --git a/core/src/test/java/com/radixdlt/rev2/protocol/AnemoneProtocolUpdateTest.java b/core/src/test/java/com/radixdlt/rev2/protocol/AnemoneProtocolUpdateTest.java index 640efc1250..1afe71b023 100644 --- a/core/src/test/java/com/radixdlt/rev2/protocol/AnemoneProtocolUpdateTest.java +++ b/core/src/test/java/com/radixdlt/rev2/protocol/AnemoneProtocolUpdateTest.java @@ -120,7 +120,7 @@ private DeterministicTest createTest(Module... extraModules) { new FunctionalRadixNodeModule( FunctionalRadixNodeModule.NodeStorageConfig.tempFolder(folder), true, - FunctionalRadixNodeModule.SafetyRecoveryConfig.BERKELEY_DB, + FunctionalRadixNodeModule.SafetyRecoveryConfig.REAL, FunctionalRadixNodeModule.ConsensusConfig.of(1000), FunctionalRadixNodeModule.LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/rev2/protocol/BottlenoseProtocolUpdateTest.java b/core/src/test/java/com/radixdlt/rev2/protocol/BottlenoseProtocolUpdateTest.java index 0816c263c5..0950b02b47 100644 --- a/core/src/test/java/com/radixdlt/rev2/protocol/BottlenoseProtocolUpdateTest.java +++ b/core/src/test/java/com/radixdlt/rev2/protocol/BottlenoseProtocolUpdateTest.java @@ -124,7 +124,7 @@ private DeterministicTest createTest(Module... extraModules) { new FunctionalRadixNodeModule( FunctionalRadixNodeModule.NodeStorageConfig.tempFolder(folder), true, - FunctionalRadixNodeModule.SafetyRecoveryConfig.BERKELEY_DB, + FunctionalRadixNodeModule.SafetyRecoveryConfig.REAL, FunctionalRadixNodeModule.ConsensusConfig.of(1000), FunctionalRadixNodeModule.LedgerConfig.stateComputerNoSync( new StateComputerConfig.REv2StateComputerConfig( diff --git a/core/src/test/java/com/radixdlt/rev2/protocol/ProtocolUpdateWithEpochBoundsTest.java b/core/src/test/java/com/radixdlt/rev2/protocol/ProtocolUpdateWithEpochBoundsTest.java index 0bb45d1a7b..384dd17dfe 100644 --- a/core/src/test/java/com/radixdlt/rev2/protocol/ProtocolUpdateWithEpochBoundsTest.java +++ b/core/src/test/java/com/radixdlt/rev2/protocol/ProtocolUpdateWithEpochBoundsTest.java @@ -291,7 +291,7 @@ private DeterministicTest createTest(ProtocolConfig protocolConfig) { new FunctionalRadixNodeModule( NodeStorageConfig.tempFolder(folder), true, - SafetyRecoveryConfig.BERKELEY_DB, + SafetyRecoveryConfig.REAL, ConsensusConfig.of(200), LedgerConfig.stateComputerNoSync( StateComputerConfig.rev2() diff --git a/core/src/test/java/com/radixdlt/utils/SerializerTestDataGenerator.java b/core/src/test/java/com/radixdlt/utils/SerializerTestDataGenerator.java index 4940f96eeb..f6945e547b 100644 --- a/core/src/test/java/com/radixdlt/utils/SerializerTestDataGenerator.java +++ b/core/src/test/java/com/radixdlt/utils/SerializerTestDataGenerator.java @@ -66,7 +66,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.hash.HashCode; import com.radixdlt.consensus.*; import com.radixdlt.consensus.bft.BFTValidator; import com.radixdlt.consensus.bft.BFTValidatorId; @@ -118,7 +117,7 @@ public static VoteData randomVoteData() { public static BFTHeader randomBFTHeader() { return new BFTHeader( randomRound(), - HashCode.fromLong(random.nextLong()), + HashUtils.random256(), LedgerHeader.create( Math.abs(random.nextLong()), randomRound(),