From 2aedbd409b61b8e192cc7521e26c5e08883286cc Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 04:30:49 +0000 Subject: [PATCH 1/8] refactor: Improved configuration of protocol updates Also, set test networks to immediately attempt to run anemone. --- .../java/com/radixdlt/networks/Network.java | 2 + .../com/radixdlt/protocol/ProtocolConfig.java | 38 ++- .../radixdlt/protocol/ProtocolConfigV0.java | 86 +++++ .../ProtocolUpdateEnactmentCondition.java | 9 +- ...Update.java => ProtocolUpdateTrigger.java} | 6 +- .../radixdlt/protocol/RustProtocolUpdate.java | 20 +- .../com/radixdlt/sbor/NodeSborCodecs.java | 2 +- .../radixdlt/statecomputer/ProtocolState.java | 6 +- .../rev2/ProtocolConfigGeneratorTest.java | 4 +- .../src/jni/node_rust_environment.rs | 14 +- .../state-manager/src/jni/protocol_update.rs | 18 +- .../state-manager/src/jni/state_computer.rs | 2 +- .../src/jni/transaction_store.rs | 3 +- core-rust/state-manager/src/lib.rs | 1 - .../src/protocol/mainnet_updates/anemone.rs | 72 ----- .../src/protocol/mainnet_updates/mod.rs | 33 -- core-rust/state-manager/src/protocol/mod.rs | 7 +- .../src/protocol/protocol_config.rs | 299 ++++++++++-------- .../by_network/mainnet_protocol_config.rs | 20 ++ .../protocol_configs/by_network/mod.rs | 7 + .../by_network/stokenet_protocol_config.rs | 17 + .../by_network/testnet_protocol_config.rs | 18 ++ .../src/protocol/protocol_configs/mod.rs | 5 + .../protocol_config_resolver.rs | 16 + .../src/protocol/protocol_state.rs | 34 +- .../definitions/anemone_definition.rs | 71 +++++ .../definitions/custom_definition.rs | 56 ++++ .../definitions/default_definition.rs | 22 ++ .../protocol_updates/definitions/mod.rs | 9 + .../definitions/test_definition.rs | 64 ++++ .../src/protocol/protocol_updates/mod.rs | 13 + .../protocol_content_overrides.rs | 81 +++++ .../protocol_definition_resolver.rs | 103 ++++++ .../protocol_update_committer.rs} | 218 ++----------- .../protocol_update_definition.rs | 124 ++++++++ .../protocol_updates/protocol_updaters.rs | 79 +++++ core-rust/state-manager/src/protocol/test.rs | 107 +++---- core-rust/state-manager/src/staging/cache.rs | 5 +- core-rust/state-manager/src/staging/result.rs | 3 +- core-rust/state-manager/src/state_computer.rs | 7 +- core-rust/state-manager/src/state_manager.rs | 82 ++--- .../state-manager/src/store/proofs_gc.rs | 25 +- .../src/transaction/ledger_transaction.rs | 2 +- .../state-manager/src/transaction/preview.rs | 8 +- .../src/transaction/series_execution.rs | 1 + .../java/com/radixdlt/RadixNodeModule.java | 11 +- .../api/system/SystemModelMapper.java | 15 +- ...artOfEpochIfValidatorsReadyCondition.java} | 48 +-- ...EpochIfValidatorsReadyConditionAllOf.java} | 30 +- ...StartOfEpochUnconditionallyCondition.java} | 34 +- ...OfEpochUnconditionallyConditionAllOf.java} | 16 +- .../ProtocolUpdateEnactmentCondition.java | 20 +- .../ProtocolUpdateEnactmentConditionType.java | 4 +- .../api/system/routes/HealthHandler.java | 10 +- .../api/system/system-api-schema.yaml | 12 +- .../com/radixdlt/rev2/REv2StateComputer.java | 5 + .../api/core/TransactionStreamTest.java | 7 +- .../com/radixdlt/p2p/test/MockP2PNetwork.java | 4 +- .../p2p/test/P2PTestNetworkRunner.java | 2 +- .../protocol/AnemoneProtocolUpdateTest.java | 7 +- .../ProtocolUpdateWithEpochBoundsTest.java | 61 ++-- 61 files changed, 1331 insertions(+), 774 deletions(-) create mode 100644 core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java rename core-rust-bridge/src/main/java/com/radixdlt/protocol/{ProtocolUpdate.java => ProtocolUpdateTrigger.java} (97%) delete mode 100644 core-rust/state-manager/src/protocol/mainnet_updates/anemone.rs delete mode 100644 core-rust/state-manager/src/protocol/mainnet_updates/mod.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/by_network/mainnet_protocol_config.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/by_network/stokenet_protocol_config.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/by_network/testnet_protocol_config.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/mod.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/definitions/anemone_definition.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/definitions/custom_definition.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/definitions/default_definition.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/definitions/mod.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/definitions/test_definition.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/mod.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs rename core-rust/state-manager/src/protocol/{protocol_update.rs => protocol_updates/protocol_update_committer.rs} (54%) create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/protocol_update_definition.rs create mode 100644 core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs rename core/src/main/java/com/radixdlt/api/system/generated/models/{EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.java => EnactAtStartOfEpochIfValidatorsReadyCondition.java} (69%) rename core/src/main/java/com/radixdlt/api/system/generated/models/{EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.java => EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.java} (76%) rename core/src/main/java/com/radixdlt/api/system/generated/models/{EnactUnconditionallyAtEpochCondition.java => EnactAtStartOfEpochUnconditionallyCondition.java} (67%) rename core/src/main/java/com/radixdlt/api/system/generated/models/{EnactUnconditionallyAtEpochConditionAllOf.java => EnactAtStartOfEpochUnconditionallyConditionAllOf.java} (81%) diff --git a/common/src/main/java/com/radixdlt/networks/Network.java b/common/src/main/java/com/radixdlt/networks/Network.java index 98e25babb6..3f17fe8cb1 100644 --- a/common/src/main/java/com/radixdlt/networks/Network.java +++ b/common/src/main/java/com/radixdlt/networks/Network.java @@ -73,6 +73,8 @@ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public enum Network { + // NOTE: For the protocol configs, see `/protocol_updates/by_network/` in `core-rust` + // These are resolved by environment from RadixNodeModule.java. /// Public Facing Permanent Networks (0x00 - 0x09) // - mainnet diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java index 1f5195b590..ea15a00863 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java @@ -65,22 +65,52 @@ package com.radixdlt.protocol; import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.radixdlt.rev2.NetworkDefinition; +import com.radixdlt.sbor.NodeSborCodecs; import com.radixdlt.sbor.codec.CodecMap; import com.radixdlt.sbor.codec.StructCodec; +import com.radixdlt.sbor.exceptions.SborDecodeException; +import java.util.Map; public record ProtocolConfig( - String genesisProtocolVersion, ImmutableList protocolUpdates) { + String genesisProtocolVersion, + ImmutableList protocolUpdateTriggers, + Map rawProtocolUpdateContentOverrides) { + + public static final String GENESIS_PROTOCOL_VERSION_NAME = "babylon-genesis"; + + public ProtocolConfig(ImmutableList protocolUpdateTriggers) { + this(protocolUpdateTriggers, Map.of()); + } + + public ProtocolConfig( + ImmutableList protocolUpdateTriggers, + Map rawProtocolUpdateContentOverrides) { + this(GENESIS_PROTOCOL_VERSION_NAME, protocolUpdateTriggers, rawProtocolUpdateContentOverrides); + } + public static void registerCodec(CodecMap codecMap) { codecMap.register( ProtocolConfig.class, codecs -> StructCodec.fromRecordComponents(ProtocolConfig.class, codecs)); } + public static ProtocolConfig sborDecodeWithFallbackForOldVersions(byte[] encoded) { + try { + return NodeSborCodecs.decode(encoded, NodeSborCodecs.resolveCodec(new TypeToken<>() {})); + } catch (SborDecodeException ex) { + return NodeSborCodecs.decode( + encoded, NodeSborCodecs.resolveCodec(new TypeToken() {})) + .update(); + } + } + public static ProtocolConfig testingDefault() { - return new ProtocolConfig("testing-genesis", ImmutableList.of()); + return new ProtocolConfig(ImmutableList.of()); } - public static ProtocolConfig mainnet() { - return RustProtocolUpdate.mainnetConfig(); + public static ProtocolConfig resolveForNetwork(NetworkDefinition networkDefinition) { + return RustProtocolUpdate.resolveForNetwork(networkDefinition); } } diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java new file mode 100644 index 0000000000..6adb873723 --- /dev/null +++ b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.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.protocol; + +import com.google.common.collect.ImmutableList; +import com.radixdlt.sbor.codec.CodecMap; +import com.radixdlt.sbor.codec.StructCodec; +import java.util.Map; + +/** + * A legacy format still used in some tests. We attempt to decode this as well as the new format. + */ +public record ProtocolConfigV0( + String genesisProtocolVersion, ImmutableList protocolUpdateTriggers) { + public static void registerCodec(CodecMap codecMap) { + codecMap.register( + ProtocolConfigV0.class, + codecs -> StructCodec.fromRecordComponents(ProtocolConfigV0.class, codecs)); + } + + public ProtocolConfig update() { + return new ProtocolConfig(genesisProtocolVersion, protocolUpdateTriggers, Map.of()); + } +} diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateEnactmentCondition.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateEnactmentCondition.java index bc7ca17e72..7600df2703 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateEnactmentCondition.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateEnactmentCondition.java @@ -97,7 +97,7 @@ static ProtocolUpdateEnactmentCondition singleReadinessThresholdBetweenEpochs( static ProtocolUpdateEnactmentCondition readinessThresholdsBetweenEpochs( long minEpoch, long maxEpoch, ImmutableList> thresholds) { - return new EnactAtStartOfAnEpochIfSupportedAndWithinBounds( + return new EnactAtStartOfEpochIfValidatorsReady( UInt64.fromNonNegativeLong(minEpoch), UInt64.fromNonNegativeLong(maxEpoch), thresholds.stream() @@ -109,10 +109,10 @@ static ProtocolUpdateEnactmentCondition readinessThresholdsBetweenEpochs( } static ProtocolUpdateEnactmentCondition unconditionallyAtEpoch(long epoch) { - return new EnactUnconditionallyAtEpoch(UInt64.fromNonNegativeLong(epoch)); + return new EnactAtStartOfEpochUnconditionally(UInt64.fromNonNegativeLong(epoch)); } - record EnactAtStartOfAnEpochIfSupportedAndWithinBounds( + record EnactAtStartOfEpochIfValidatorsReady( UInt64 lowerBoundInclusive, UInt64 upperBoundExclusive, ImmutableList readinessThresholds) @@ -127,5 +127,6 @@ public static void registerCodec(CodecMap codecMap) { } } - record EnactUnconditionallyAtEpoch(UInt64 epoch) implements ProtocolUpdateEnactmentCondition {} + record EnactAtStartOfEpochUnconditionally(UInt64 epoch) + implements ProtocolUpdateEnactmentCondition {} } diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdate.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateTrigger.java similarity index 97% rename from core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdate.java rename to core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateTrigger.java index f992e05a4c..61cffc03a9 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdate.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolUpdateTrigger.java @@ -67,15 +67,15 @@ import com.radixdlt.sbor.codec.CodecMap; import com.radixdlt.sbor.codec.StructCodec; -public record ProtocolUpdate( +public record ProtocolUpdateTrigger( String nextProtocolVersion, ProtocolUpdateEnactmentCondition enactmentCondition) { public static final String ANEMONE = "anemone"; public static void registerCodec(CodecMap codecMap) { codecMap.register( - ProtocolUpdate.class, - codecs -> StructCodec.fromRecordComponents(ProtocolUpdate.class, codecs)); + ProtocolUpdateTrigger.class, + codecs -> StructCodec.fromRecordComponents(ProtocolUpdateTrigger.class, codecs)); } public String readinessSignalName() { diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/RustProtocolUpdate.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/RustProtocolUpdate.java index eb519e93e3..771966fe9b 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/protocol/RustProtocolUpdate.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/protocol/RustProtocolUpdate.java @@ -64,12 +64,10 @@ package com.radixdlt.protocol; -import static com.radixdlt.lang.Tuple.tuple; - import com.google.common.reflect.TypeToken; import com.radixdlt.environment.NodeRustEnvironment; -import com.radixdlt.lang.Tuple; import com.radixdlt.monitoring.Metrics; +import com.radixdlt.rev2.NetworkDefinition; import com.radixdlt.sbor.Natives; public final class RustProtocolUpdate { @@ -96,21 +94,21 @@ private static native byte[] applyProtocolUpdate( private final Natives.Call1 applyProtocolUpdateFunc; - public static String readinessSignalName(ProtocolUpdate protocolUpdate) { - return readinessSignalNameFunc.call(protocolUpdate); + public static String readinessSignalName(ProtocolUpdateTrigger protocolUpdateTrigger) { + return readinessSignalNameFunc.call(protocolUpdateTrigger); } - private static final Natives.Call1 readinessSignalNameFunc = + private static final Natives.Call1 readinessSignalNameFunc = Natives.builder(RustProtocolUpdate::nativeReadinessSignalName).build(new TypeToken<>() {}); private static native byte[] nativeReadinessSignalName(byte[] requestPayload); - public static ProtocolConfig mainnetConfig() { - return mainnetConfigFunc.call(tuple()); + public static ProtocolConfig resolveForNetwork(NetworkDefinition networkDefinition) { + return resolveForNetworkFunc.call(networkDefinition); } - private static final Natives.Call1 mainnetConfigFunc = - Natives.builder(RustProtocolUpdate::nativeMainnetConfig).build(new TypeToken<>() {}); + private static final Natives.Call1 resolveForNetworkFunc = + Natives.builder(RustProtocolUpdate::nativeResolveForNetwork).build(new TypeToken<>() {}); - private static native byte[] nativeMainnetConfig(byte[] requestPayload); + private static native byte[] nativeResolveForNetwork(byte[] requestPayload); } 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 44b4602aae..b7b7e1b4d9 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 @@ -125,7 +125,7 @@ public static void registerCodecsWithCodecMap(CodecMap codecMap) { LoggingConfig.registerCodec(codecMap); StateManagerConfig.registerCodec(codecMap); ProtocolConfig.registerCodec(codecMap); - ProtocolUpdate.registerCodec(codecMap); + ProtocolUpdateTrigger.registerCodec(codecMap); ProtocolUpdateEnactmentCondition.registerCodec(codecMap); ProtocolUpdateEnactmentCondition.SignalledReadinessThreshold.registerCodec(codecMap); ProtocolState.registerCodec(codecMap); diff --git a/core-rust-bridge/src/main/java/com/radixdlt/statecomputer/ProtocolState.java b/core-rust-bridge/src/main/java/com/radixdlt/statecomputer/ProtocolState.java index ee7e929190..16b1c15dc5 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/statecomputer/ProtocolState.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/statecomputer/ProtocolState.java @@ -67,8 +67,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.radixdlt.lang.Tuple; -import com.radixdlt.protocol.ProtocolUpdate; import com.radixdlt.protocol.ProtocolUpdateEnactmentCondition; +import com.radixdlt.protocol.ProtocolUpdateTrigger; import com.radixdlt.sbor.codec.CodecMap; import com.radixdlt.sbor.codec.EnumCodec; import com.radixdlt.sbor.codec.StructCodec; @@ -101,11 +101,11 @@ public static void registerCodec(CodecMap codecMap) { } public static ProtocolState testingEmpty() { - return new ProtocolState("testing-genesis", ImmutableMap.of(), ImmutableList.of()); + return new ProtocolState("babylon-genesis", ImmutableMap.of(), ImmutableList.of()); } public record PendingProtocolUpdate( - ProtocolUpdate protocolUpdate, PendingProtocolUpdateState state) {} + ProtocolUpdateTrigger protocolUpdateTrigger, PendingProtocolUpdateState state) {} public sealed interface PendingProtocolUpdateState { record ForSignalledReadinessSupportCondition( diff --git a/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java b/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java index 1103a8b215..92338f40d1 100644 --- a/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java +++ b/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java @@ -67,8 +67,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.reflect.TypeToken; import com.radixdlt.protocol.ProtocolConfig; -import com.radixdlt.protocol.ProtocolUpdate; import com.radixdlt.protocol.ProtocolUpdateEnactmentCondition; +import com.radixdlt.protocol.ProtocolUpdateTrigger; import com.radixdlt.sbor.NodeSborCodecs; import org.bouncycastle.util.encoders.Hex; import org.junit.Ignore; @@ -84,7 +84,7 @@ public void generateProtocolConfig() { new ProtocolConfig( "babylon-genesis", ImmutableList.of( - new ProtocolUpdate( + new ProtocolUpdateTrigger( "v2", ProtocolUpdateEnactmentCondition.singleReadinessThresholdBetweenEpochs( 5, 20, Decimal.ofNonNegativeFraction(7, 10), 1)))); 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 585f6b9954..fbb8fe5a89 100644 --- a/core-rust/state-manager/src/jni/node_rust_environment.rs +++ b/core-rust/state-manager/src/jni/node_rust_environment.rs @@ -87,11 +87,7 @@ use crate::store::StateManagerDatabase; use super::fatal_panic_handler::FatalPanicHandler; -use crate::mainnet_updates::ProductionProtocolUpdaterFactory; -use crate::{ - ProtocolUpdaterFactory, StateComputer, StateManager, StateManagerConfig, - TestingDefaultProtocolUpdaterFactory, -}; +use crate::{StateComputer, StateManager, StateManagerConfig}; const POINTER_JNI_FIELD_NAME: &str = "rustNodeRustEnvironmentPointer"; @@ -155,18 +151,10 @@ impl JNINodeRustEnvironment { .track_running_tasks() .measured(metric_registry.deref()); - let protocol_updater_factory: Box = - if network.id == NetworkDefinition::mainnet().id { - Box::new(ProductionProtocolUpdaterFactory::new(network.clone())) - } else { - Box::new(TestingDefaultProtocolUpdaterFactory::new(network.clone())) - }; - let state_manager = StateManager::new( config, Some(MempoolRelayDispatcher::new(env, j_node_rust_env).unwrap()), &lock_factory, - protocol_updater_factory, &metric_registry, &scheduler, ); diff --git a/core-rust/state-manager/src/jni/protocol_update.rs b/core-rust/state-manager/src/jni/protocol_update.rs index dc67865f09..92988be1bb 100644 --- a/core-rust/state-manager/src/jni/protocol_update.rs +++ b/core-rust/state-manager/src/jni/protocol_update.rs @@ -62,7 +62,7 @@ * permissions under this License. */ -use crate::{ProtocolConfig, ProtocolUpdate, ProtocolUpdateResult}; +use crate::{protocol::*, ProtocolUpdateResult}; use jni::objects::{JClass, JObject}; use jni::sys::jbyteArray; use jni::JNIEnv; @@ -101,18 +101,24 @@ extern "system" fn Java_com_radixdlt_protocol_RustProtocolUpdate_nativeReadiness _class: JClass, request_payload: jbyteArray, ) -> jbyteArray { - jni_sbor_coded_call(&env, request_payload, |protocol_update: ProtocolUpdate| { - protocol_update.readiness_signal_name() - }) + jni_sbor_coded_call( + &env, + request_payload, + |protocol_update_trigger: ProtocolUpdateTrigger| { + protocol_update_trigger.readiness_signal_name() + }, + ) } #[no_mangle] -extern "system" fn Java_com_radixdlt_protocol_RustProtocolUpdate_nativeMainnetConfig( +extern "system" fn Java_com_radixdlt_protocol_RustProtocolUpdate_nativeResolveForNetwork( env: JNIEnv, _class: JClass, request_payload: jbyteArray, ) -> jbyteArray { - jni_sbor_coded_call(&env, request_payload, |_: ()| ProtocolConfig::mainnet()) + jni_sbor_coded_call(&env, request_payload, |network: NetworkDefinition| { + ProtocolConfigResolver::resolve_config(&network) + }) } pub fn export_extern_functions() {} diff --git a/core-rust/state-manager/src/jni/state_computer.rs b/core-rust/state-manager/src/jni/state_computer.rs index b3c0d00008..36356bef45 100644 --- a/core-rust/state-manager/src/jni/state_computer.rs +++ b/core-rust/state-manager/src/jni/state_computer.rs @@ -62,7 +62,7 @@ * permissions under this License. */ -use crate::{CommitSummary, LedgerProof, ProtocolState}; +use crate::{protocol::ProtocolState, CommitSummary, LedgerProof}; use jni::objects::{JClass, JObject}; use jni::sys::jbyteArray; use jni::JNIEnv; diff --git a/core-rust/state-manager/src/jni/transaction_store.rs b/core-rust/state-manager/src/jni/transaction_store.rs index 5cf7b818db..c9e50da2c0 100644 --- a/core-rust/state-manager/src/jni/transaction_store.rs +++ b/core-rust/state-manager/src/jni/transaction_store.rs @@ -64,8 +64,9 @@ use crate::jni::node_rust_environment::JNINodeRustEnvironment; use crate::jni::LedgerSyncLimitsConfig; +use crate::protocol::epoch_change_iter; use crate::store::traits::*; -use crate::{epoch_change_iter, LedgerProof, StateVersion}; +use crate::{LedgerProof, StateVersion}; use jni::objects::{JClass, JObject}; use jni::sys::jbyteArray; use jni::JNIEnv; diff --git a/core-rust/state-manager/src/lib.rs b/core-rust/state-manager/src/lib.rs index 53662ee6db..552b8097e9 100644 --- a/core-rust/state-manager/src/lib.rs +++ b/core-rust/state-manager/src/lib.rs @@ -85,7 +85,6 @@ mod test; pub use crate::mempool::*; pub use crate::metrics::*; pub use crate::pending_transaction_result_cache::*; -pub use crate::protocol::*; pub use crate::receipt::*; pub use crate::staging::*; pub use crate::state_computer::*; diff --git a/core-rust/state-manager/src/protocol/mainnet_updates/anemone.rs b/core-rust/state-manager/src/protocol/mainnet_updates/anemone.rs deleted file mode 100644 index a2c60d3a5e..0000000000 --- a/core-rust/state-manager/src/protocol/mainnet_updates/anemone.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::transaction::FlashTransactionV1; -use crate::{ - ProtocolUpdateFlashTxnCommitter, ProtocolUpdater, StateManagerDatabase, - UpdatableStateComputerConfig, ANEMONE_PROTOCOL_VERSION, -}; -use node_common::locks::StateLock; -use radix_engine::utils::{ - generate_pools_v1_1_state_updates, generate_seconds_precision_state_updates, - generate_validator_fee_fix_state_updates, generate_vm_boot_scrypto_minor_version_state_updates, -}; -use radix_engine_common::prelude::NetworkDefinition; -use std::ops::Deref; -use std::sync::Arc; - -pub struct AnemoneProtocolUpdater { - pub network: NetworkDefinition, -} - -impl ProtocolUpdater for AnemoneProtocolUpdater { - fn updatable_config(&self) -> UpdatableStateComputerConfig { - UpdatableStateComputerConfig::default(self.network.clone()) - } - - fn execute_remaining_state_updates(&self, store: Arc>) { - // We're using the new configuration to execute the protocol update - // transactions (although it's not a requirement). - let updatable_config = self.updatable_config(); - let mut txn_committer = ProtocolUpdateFlashTxnCommitter::new( - ANEMONE_PROTOCOL_VERSION.to_string(), - store.clone(), - updatable_config.execution_configurator(true), /* No fees for protocol updates */ - updatable_config.ledger_transaction_validator(), - ); - - while let Some(next_batch_idx) = txn_committer.next_committable_batch_idx() { - match next_batch_idx { - 0 => { - // Just a single batch for Anemone, which includes - // the following transactions: - let flash_txns = { - let read_db = store.read_current(); - vec![ - FlashTransactionV1 { - name: "anemone-validator-fee-fix".to_string(), - state_updates: generate_validator_fee_fix_state_updates( - read_db.deref(), - ), - }, - FlashTransactionV1 { - name: "anemone-seconds-precision".to_string(), - state_updates: generate_seconds_precision_state_updates( - read_db.deref(), - ), - }, - FlashTransactionV1 { - name: "anemone-vm-boot".to_string(), - state_updates: generate_vm_boot_scrypto_minor_version_state_updates( - ), - }, - FlashTransactionV1 { - name: "anemone-pools".to_string(), - state_updates: generate_pools_v1_1_state_updates(read_db.deref()), - }, - ] - }; - txn_committer.commit_flash_batch(flash_txns); - } - _ => break, - } - } - } -} diff --git a/core-rust/state-manager/src/protocol/mainnet_updates/mod.rs b/core-rust/state-manager/src/protocol/mainnet_updates/mod.rs deleted file mode 100644 index 456e31a295..0000000000 --- a/core-rust/state-manager/src/protocol/mainnet_updates/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -mod anemone; - -use crate::mainnet_updates::anemone::AnemoneProtocolUpdater; -use crate::{ - NoStateUpdatesProtocolUpdater, ProtocolUpdater, ProtocolUpdaterFactory, - ANEMONE_PROTOCOL_VERSION, GENESIS_PROTOCOL_VERSION, -}; - -use radix_engine_common::network::NetworkDefinition; - -pub struct ProductionProtocolUpdaterFactory { - network: NetworkDefinition, -} - -impl ProductionProtocolUpdaterFactory { - pub fn new(network: NetworkDefinition) -> ProductionProtocolUpdaterFactory { - ProductionProtocolUpdaterFactory { network } - } -} - -impl ProtocolUpdaterFactory for ProductionProtocolUpdaterFactory { - fn updater_for(&self, protocol_version_name: &str) -> Option> { - match protocol_version_name { - GENESIS_PROTOCOL_VERSION => Some(Box::new(NoStateUpdatesProtocolUpdater::default( - self.network.clone(), - ))), - ANEMONE_PROTOCOL_VERSION => Some(Box::new(AnemoneProtocolUpdater { - network: self.network.clone(), - })), - _ => None, - } - } -} diff --git a/core-rust/state-manager/src/protocol/mod.rs b/core-rust/state-manager/src/protocol/mod.rs index 9298ef9e48..d811d49675 100644 --- a/core-rust/state-manager/src/protocol/mod.rs +++ b/core-rust/state-manager/src/protocol/mod.rs @@ -1,11 +1,12 @@ -pub mod mainnet_updates; mod protocol_config; +mod protocol_configs; mod protocol_state; -mod protocol_update; +mod protocol_updates; #[cfg(test)] mod test; pub use protocol_config::*; +pub use protocol_configs::*; pub use protocol_state::*; -pub use protocol_update::*; +pub use protocol_updates::*; diff --git a/core-rust/state-manager/src/protocol/protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_config.rs index b57acf057b..de809c74b6 100644 --- a/core-rust/state-manager/src/protocol/protocol_config.rs +++ b/core-rust/state-manager/src/protocol/protocol_config.rs @@ -1,38 +1,168 @@ -use radix_engine::prelude::{dec, ScryptoCategorize, ScryptoDecode, ScryptoEncode}; +use radix_engine::prelude::ScryptoSbor; use radix_engine_common::math::Decimal; use radix_engine_common::prelude::{hash, scrypto_encode}; use radix_engine_common::types::Epoch; -use crate::ProtocolUpdaterFactory; +use crate::protocol::*; use utils::btreeset; // This file contains types for node's local static protocol configuration -pub const GENESIS_PROTOCOL_VERSION: &str = "babylon-genesis"; -pub const ANEMONE_PROTOCOL_VERSION: &str = "anemone"; - const MAX_PROTOCOL_VERSION_NAME_LEN: usize = 16; -/// Returns a protocol version name left padded to canonical length (16 bytes) -pub fn padded_protocol_version_name(unpadded_protocol_version_name: &str) -> String { - let mut res = "".to_owned(); - for _ in 0..16 - unpadded_protocol_version_name.len() { - res.push('0'); +/// The `ProtocolConfig` is a static configuration provided per-network, or overriden for testing. +/// +/// When a node commits (or creates a proof), it checks `protocol_update_triggers` to see if a protocol update +/// should be triggered next. +/// +/// If the update is triggered, any relevant overrides are combined with the `protocol_definition_resolver` to +/// work out what it should do for the update. +#[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] +pub struct ProtocolConfig { + pub genesis_protocol_version: String, + pub protocol_update_triggers: Vec, + /// This allows overriding the configuration of a protocol update. + /// + /// You can create this with `ProtocolUpdateContentOverrides::empty().into()` or `Default::default()`. + /// + /// This wraps an optional `Map>` where the `Vec` is the encoded config + /// for the protocol updater matching the given protocol update. + /// + /// All nodes must agree on the content overrides used. The content overrides form a part of + /// the definition of the protocol update, and if nodes use different overrides, they will execute + /// different updates and need manual recovery. + pub protocol_update_content_overrides: RawProtocolUpdateContentOverrides, +} + +impl ProtocolConfig { + pub fn new_with_no_updates() -> ProtocolConfig { + Self { + genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), + protocol_update_triggers: vec![], + protocol_update_content_overrides: RawProtocolUpdateContentOverrides::default(), + } + } + + pub fn new_with_triggers<'a>( + triggers: impl IntoIterator, + ) -> ProtocolConfig { + Self { + genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), + protocol_update_triggers: triggers + .into_iter() + .map(|(version, enactment_condition)| { + ProtocolUpdateTrigger::of(version, enactment_condition) + }) + .collect(), + protocol_update_content_overrides: RawProtocolUpdateContentOverrides::default(), + } + } + + pub fn validate( + &self, + protocol_definition_resolver: &ProtocolDefinitionResolver, + ) -> Result<(), String> { + let mut protocol_versions = btreeset!(); + + Self::validate_protocol_version_name( + self.genesis_protocol_version.as_str(), + protocol_definition_resolver, + )?; + + for protocol_update in self.protocol_update_triggers.iter() { + let protocol_version_name = protocol_update.next_protocol_version.as_str(); + Self::validate_protocol_version_name( + protocol_version_name, + protocol_definition_resolver, + )?; + + if !protocol_versions.insert(protocol_version_name) { + return Err(format!( + "Duplicate specification of protocol version {protocol_version_name}" + )); + } + + match &protocol_update.enactment_condition { + ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochIfValidatorsReady { + lower_bound_inclusive, + upper_bound_exclusive, + readiness_thresholds, + } => { + if lower_bound_inclusive >= upper_bound_exclusive { + return Err(format!("Protocol update {protocol_version_name} has an empty [inclusive lower bound, exclusive upper bound) range")); + } + if readiness_thresholds.is_empty() { + return Err(format!( + "Protocol update {protocol_version_name} does not specify at least one readiness threshold" + )); + } + for threshold in readiness_thresholds { + if threshold.required_ratio_of_stake_supported <= Decimal::zero() + || threshold.required_ratio_of_stake_supported > Decimal::one() + { + return Err(format!( + "Protocol update {protocol_version_name} does not have a ratio of stake supported must be between 0 (exclusive) and 1 (inclusive)" + )); + } + } + } + ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally(_) => { + // Nothing to check here + } + } + } + + // Note - The protocol_update_content_overrides are validated in the ProtocolDefinitionResolver::new_with_raw_overrides + + Ok(()) + } + + fn validate_protocol_version_name( + name: &str, + protocol_definition_resolver: &ProtocolDefinitionResolver, + ) -> Result<(), String> { + if name.len() > MAX_PROTOCOL_VERSION_NAME_LEN { + return Err(format!( + "Protocol version ({name}) is longer than {MAX_PROTOCOL_VERSION_NAME_LEN} chars" + )); + } + + if !name.is_ascii() { + return Err(format!( + "Protocol version ({name}) can't use non-ascii characters" + )); + } + + if !protocol_definition_resolver.recognizes(name) { + return Err(format!( + "Protocol version ({name}) does not have a recognized definition" + )); + } + + Ok(()) } - res.push_str(unpadded_protocol_version_name); - res } -#[derive(Clone, Debug, Eq, PartialEq, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] -pub struct ProtocolUpdate { +#[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] +pub struct ProtocolUpdateTrigger { pub next_protocol_version: String, pub enactment_condition: ProtocolUpdateEnactmentCondition, } -impl ProtocolUpdate { +impl ProtocolUpdateTrigger { + pub fn of( + next_protocol_version: impl Into, + enactment_condition: ProtocolUpdateEnactmentCondition, + ) -> Self { + Self { + next_protocol_version: next_protocol_version.into(), + enactment_condition, + } + } + pub fn readiness_signal_name(&self) -> String { - // Readiness signal name is 32 bytes long and consists of: + // Readiness signal name is 32 ASCII characters long and consists of: // - 16 hexadecimal chars of leading bytes of `hash(enactment_condition + next_protocol_version)` // - next_protocol_version: 16 bytes, // left padded with ASCII 0's if protocol version name is shorter than 16 characters @@ -40,23 +170,38 @@ impl ProtocolUpdate { bytes_to_hash.extend_from_slice(self.next_protocol_version.as_bytes()); let protocol_update_hash = hash(&bytes_to_hash); let mut res = hex::encode(protocol_update_hash)[0..16].to_string(); - res.push_str(&padded_protocol_version_name(&self.next_protocol_version)); + res.push_str(&ascii_protocol_version_name_len_16( + &self.next_protocol_version, + )); res } } -#[derive(Clone, Debug, Eq, PartialEq, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] -pub struct ProtocolConfig { - pub genesis_protocol_version: String, - pub protocol_updates: Vec, +/// Returns an ASCII protocol version name truncated/left padded to canonical length (16 bytes) +pub fn ascii_protocol_version_name_len_16(protocol_version_name: &str) -> String { + let filtered_version_name: String = protocol_version_name + .chars() + .filter_map(|c| match c { + _ if c.is_ascii_alphanumeric() => Some(c), + '_' | '-' => Some(c), + ' ' => Some('_'), + _ => None, + }) + .take(16) + .collect(); + + std::iter::repeat('0') + .take(16 - filtered_version_name.len()) + .chain(filtered_version_name.chars()) + .collect() } -#[derive(Clone, Debug, Eq, PartialEq, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +#[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] pub enum ProtocolUpdateEnactmentCondition { /// The enactment only proceeds if it's the start of epoch X, /// at least one readiness threshold is met, and X satisfies /// `lower_bound_inclusive <= X < upper_bound_exclusive`. - EnactAtStartOfAnEpochIfSupportedAndWithinBounds { + EnactAtStartOfEpochIfValidatorsReady { /// Minimum epoch at which the protocol update can be enacted (inclusive) lower_bound_inclusive: Epoch, /// Maximum epoch at which the protocol update can be enacted (exclusive) @@ -67,10 +212,10 @@ pub enum ProtocolUpdateEnactmentCondition { }, /// The enactment proceeds unconditionally /// at the start of specified epoch. - EnactUnconditionallyAtEpoch(Epoch), + EnactAtStartOfEpochUnconditionally(Epoch), } -#[derive(Clone, Debug, Eq, PartialEq, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] +#[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] pub struct SignalledReadinessThreshold { /// Required stake threshold (inclusive). Evaluated at an epoch change using validators /// from the _next_ epoch validator set. @@ -84,107 +229,3 @@ pub struct SignalledReadinessThreshold { /// "enact at the beginning of the _next_ epoch (if it still has enough support)" pub required_consecutive_completed_epochs_of_support: u64, } - -impl ProtocolConfig { - pub fn mainnet() -> ProtocolConfig { - // TODO(anemone): update the epoch bounds and thresholds - Self { - genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), - protocol_updates: vec![ProtocolUpdate { - next_protocol_version: ANEMONE_PROTOCOL_VERSION.to_string(), - enactment_condition: - ProtocolUpdateEnactmentCondition::EnactAtStartOfAnEpochIfSupportedAndWithinBounds { - lower_bound_inclusive: Epoch::of(10000), - upper_bound_exclusive: Epoch::of(20000), - readiness_thresholds: vec![SignalledReadinessThreshold { - required_ratio_of_stake_supported: dec!("0.80"), - required_consecutive_completed_epochs_of_support: 10, - }], - }, - }], - } - } - - pub fn no_updates(genesis_protocol_version: String) -> ProtocolConfig { - Self { - genesis_protocol_version, - protocol_updates: vec![], - } - } - - pub fn sanity_check( - &self, - protocol_updater_factory: &(dyn ProtocolUpdaterFactory + Send + Sync), - ) -> Result<(), String> { - let mut protocol_versions = btreeset!(); - - if self.genesis_protocol_version.len() > MAX_PROTOCOL_VERSION_NAME_LEN { - return Err("Genesis protocol version name is too long".to_string()); - } - - if !self.genesis_protocol_version.is_ascii() { - return Err("Genesis protocol version name can't use non-ascii characters".to_string()); - } - - if protocol_updater_factory - .updater_for(self.genesis_protocol_version.as_str()) - .is_none() - { - return Err( - "Protocol updater factory does not support genesis protocol version".to_string(), - ); - } - - for protocol_update in self.protocol_updates.iter() { - if protocol_update.next_protocol_version.len() > MAX_PROTOCOL_VERSION_NAME_LEN { - return Err("Protocol version name is too long".to_string()); - } - - if !protocol_update.next_protocol_version.is_ascii() { - return Err("Protocol version name can't use non-ascii characters".to_string()); - } - - if protocol_updater_factory - .updater_for(protocol_update.next_protocol_version.as_str()) - .is_none() - { - return Err("Protocol updater factory does not support a configured update protocol version".to_string()); - } - - protocol_versions.insert(&protocol_update.next_protocol_version); - - match &protocol_update.enactment_condition { - ProtocolUpdateEnactmentCondition::EnactAtStartOfAnEpochIfSupportedAndWithinBounds { - lower_bound_inclusive, - upper_bound_exclusive, - readiness_thresholds, - } => { - if lower_bound_inclusive >= upper_bound_exclusive { - return Err("Upper bound must be greater than lower bound".to_string()); - } - if readiness_thresholds.is_empty() { - return Err( - "Protocol update must specify at least one threshold".to_string() - ); - } - for threshold in readiness_thresholds { - if threshold.required_ratio_of_stake_supported <= Decimal::zero() - || threshold.required_ratio_of_stake_supported > Decimal::one() - { - return Err("Required ratio of stake supported must be between 0 (exclusive) and 1 (inclusive)".to_string()); - } - } - } - ProtocolUpdateEnactmentCondition::EnactUnconditionallyAtEpoch(_) => { - // Nothing to check here - } - } - } - - if protocol_versions.len() != self.protocol_updates.len() { - return Err("Protocol versions must have unique names".to_string()); - } - - Ok(()) - } -} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mainnet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mainnet_protocol_config.rs new file mode 100644 index 0000000000..5e00fad667 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mainnet_protocol_config.rs @@ -0,0 +1,20 @@ +use radix_engine::prelude::*; + +use crate::protocol::*; +use ProtocolUpdateEnactmentCondition::*; + +pub fn mainnet_protocol_config() -> ProtocolConfig { + ProtocolConfig::new_with_triggers(hashmap! { + ANEMONE_PROTOCOL_VERSION => EnactAtStartOfEpochIfValidatorsReady { + // TODO(anemone): update the epoch bounds and thresholds + lower_bound_inclusive: Epoch::of(10000), + upper_bound_exclusive: Epoch::of(20000), + readiness_thresholds: vec![ + SignalledReadinessThreshold { + required_ratio_of_stake_supported: dec!("0.80"), + required_consecutive_completed_epochs_of_support: 10, + } + ], + } + }) +} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs new file mode 100644 index 0000000000..8def1d0306 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs @@ -0,0 +1,7 @@ +mod mainnet_protocol_config; +mod stokenet_protocol_config; +mod testnet_protocol_config; + +pub use mainnet_protocol_config::*; +pub use stokenet_protocol_config::*; +pub use testnet_protocol_config::*; diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/stokenet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/stokenet_protocol_config.rs new file mode 100644 index 0000000000..78f4699906 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/by_network/stokenet_protocol_config.rs @@ -0,0 +1,17 @@ +use radix_engine::prelude::*; + +use crate::protocol::*; +use ProtocolUpdateEnactmentCondition::*; + +pub fn stokenet_protocol_config() -> ProtocolConfig { + ProtocolConfig::new_with_triggers(hashmap! { + ANEMONE_PROTOCOL_VERSION => EnactAtStartOfEpochIfValidatorsReady { + lower_bound_inclusive: Epoch::of(1), + upper_bound_exclusive: Epoch::of(1000000), + readiness_thresholds: vec![SignalledReadinessThreshold { + required_ratio_of_stake_supported: dec!("0.80"), + required_consecutive_completed_epochs_of_support: 10, + }], + } + }) +} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/testnet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/testnet_protocol_config.rs new file mode 100644 index 0000000000..fab239156b --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/by_network/testnet_protocol_config.rs @@ -0,0 +1,18 @@ +use radix_engine::prelude::*; + +use crate::protocol::*; +use ProtocolUpdateEnactmentCondition::*; + +pub fn testnet_protocol_config() -> ProtocolConfig { + // We wish most testnets to upgrade to the latest protocol version as soon as they can... + // Currently we can only enact protocol updates after the end of a "normal" epoch. + // + // On testnets: + // * Epoch 1 is genesis + // * Epoch 2 is the first normal epoch + // + // So we should target applying protocol updates from 3 onwards (1 per epoch) + ProtocolConfig::new_with_triggers(hashmap! { + ANEMONE_PROTOCOL_VERSION => EnactAtStartOfEpochUnconditionally(Epoch::of(3)) + }) +} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/mod.rs b/core-rust/state-manager/src/protocol/protocol_configs/mod.rs new file mode 100644 index 0000000000..4ab6cca19f --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/mod.rs @@ -0,0 +1,5 @@ +mod by_network; +mod protocol_config_resolver; + +pub use by_network::*; +pub use protocol_config_resolver::*; diff --git a/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs b/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs new file mode 100644 index 0000000000..dc78294ff7 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs @@ -0,0 +1,16 @@ +use super::by_network::*; +use crate::protocol::*; + +use radix_engine_common::network::NetworkDefinition; + +pub struct ProtocolConfigResolver; + +impl ProtocolConfigResolver { + pub fn resolve_config(network: &NetworkDefinition) -> ProtocolConfig { + match network.logical_name.as_str() { + "mainnet" => mainnet_protocol_config(), + "stokenet" => stokenet_protocol_config(), + _ => testnet_protocol_config(), + } + } +} diff --git a/core-rust/state-manager/src/protocol/protocol_state.rs b/core-rust/state-manager/src/protocol/protocol_state.rs index da36c3ae30..1a270f3199 100644 --- a/core-rust/state-manager/src/protocol/protocol_state.rs +++ b/core-rust/state-manager/src/protocol/protocol_state.rs @@ -14,14 +14,10 @@ use radix_engine_interface::prelude::CheckedMul; use radix_engine_interface::prelude::Emitter; use tracing::info; +use crate::protocol::*; use crate::traits::{IterableProofStore, QueryableProofStore, QueryableTransactionStore}; -use crate::ProtocolUpdateEnactmentCondition::{ - EnactAtStartOfAnEpochIfSupportedAndWithinBounds, EnactUnconditionallyAtEpoch, -}; -use crate::{ - LocalTransactionReceipt, ProtocolConfig, ProtocolUpdate, SignalledReadinessThreshold, - StateVersion, -}; +use crate::{LocalTransactionReceipt, StateVersion}; +use ProtocolUpdateEnactmentCondition::*; // This file contains types and utilities for // managing the (dynamic) protocol state of a running node. @@ -35,7 +31,7 @@ pub struct ProtocolState { #[derive(Clone, Debug, Eq, PartialEq, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] pub struct PendingProtocolUpdate { - pub protocol_update: ProtocolUpdate, + pub protocol_update: ProtocolUpdateTrigger, pub state: PendingProtocolUpdateState, } @@ -71,21 +67,21 @@ fn compute_initial_protocol_update_status< S: QueryableProofStore + IterableProofStore + QueryableTransactionStore, >( store: &S, - protocol_update: &ProtocolUpdate, + protocol_change: &ProtocolUpdateTrigger, ) -> InitialProtocolUpdateStatus { - match &protocol_update.enactment_condition { - EnactAtStartOfAnEpochIfSupportedAndWithinBounds { + match &protocol_change.enactment_condition { + EnactAtStartOfEpochIfValidatorsReady { lower_bound_inclusive, upper_bound_exclusive, readiness_thresholds, } => compute_initial_signalled_readiness_protocol_update_status( store, - protocol_update, + protocol_change, lower_bound_inclusive, upper_bound_exclusive, readiness_thresholds, ), - EnactUnconditionallyAtEpoch(epoch) => { + EnactAtStartOfEpochUnconditionally(epoch) => { compute_initial_at_epoch_protocol_update_status(store, *epoch) } } @@ -95,7 +91,7 @@ fn compute_initial_signalled_readiness_protocol_update_status< S: QueryableProofStore + IterableProofStore + QueryableTransactionStore, >( store: &S, - protocol_update: &ProtocolUpdate, + protocol_update: &ProtocolUpdateTrigger, lower_bound_inclusive: &Epoch, upper_bound_exclusive: &Epoch, thresholds: &[SignalledReadinessThreshold], @@ -193,7 +189,7 @@ impl ProtocolState { store: &S, protocol_config: &ProtocolConfig, ) -> ProtocolState { - // For each configured protocol update we calculate it's expected status against + // For each configured allowed protocol update we calculate its expected status against // the current state of the ledger, regardless of any information stored // about the protocol updates that were actually enacted. // This is then juxtaposed with the protocol updates that have actually been enacted, @@ -204,7 +200,7 @@ impl ProtocolState { // This also provides the initial state for stateful (readiness-based) // protocol update conditions. let initial_statuses: Vec<_> = protocol_config - .protocol_updates + .protocol_update_triggers .iter() .map(|protocol_update| { ( @@ -304,7 +300,7 @@ impl ProtocolState { let mut enactable_protocol_updates = vec![]; for mut pending_protocol_update in new_protocol_state.pending_protocol_updates { match &pending_protocol_update.protocol_update.enactment_condition { - EnactAtStartOfAnEpochIfSupportedAndWithinBounds { + EnactAtStartOfEpochIfValidatorsReady { lower_bound_inclusive, upper_bound_exclusive, .. @@ -350,7 +346,7 @@ impl ProtocolState { expired_protocol_updates.push(pending_protocol_update); } } - EnactUnconditionallyAtEpoch(enactment_epoch) => { + EnactAtStartOfEpochUnconditionally(enactment_epoch) => { if let Some(next_epoch) = &local_receipt.local_execution.next_epoch { match next_epoch.epoch.cmp(enactment_epoch) { Ordering::Less => { @@ -420,7 +416,7 @@ fn any_threshold_passes( } fn update_thresholds_state_at_epoch_change( - protocol_update: &ProtocolUpdate, + protocol_update: &ProtocolUpdateTrigger, epoch_change_event: &EpochChangeEvent, thresholds_state: &mut Vec<( SignalledReadinessThreshold, 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 new file mode 100644 index 0000000000..afeec4f625 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/anemone_definition.rs @@ -0,0 +1,71 @@ +use crate::protocol::*; +use crate::transaction::FlashTransactionV1; +use radix_engine::types::*; +use radix_engine::utils::{ + generate_pools_v1_1_state_updates, generate_seconds_precision_state_updates, + generate_validator_fee_fix_state_updates, generate_vm_boot_scrypto_minor_version_state_updates, +}; +use radix_engine_store_interface::interface::SubstateDatabase; + +pub struct AnemoneProtocolUpdateDefinition; + +impl ProtocolUpdateDefinition for AnemoneProtocolUpdateDefinition { + type Overrides = (); + + fn create_updater( + new_protocol_version: &str, + network_definition: &NetworkDefinition, + _config: Option, + ) -> Box { + Box::new(BatchedUpdater::new( + new_protocol_version.to_string(), + Self::state_computer_config(network_definition), + AnemoneBatchGenerator, + )) + } + + fn state_computer_config( + network_definition: &NetworkDefinition, + ) -> ProtocolStateComputerConfig { + ProtocolStateComputerConfig::default(network_definition.clone()) + } +} + +struct AnemoneBatchGenerator; + +impl UpdateBatchGenerator for AnemoneBatchGenerator { + fn generate_batch( + &self, + store: &impl SubstateDatabase, + batch_index: u32, + ) -> Option> { + match batch_index { + 0 => { + // Just a single batch for Anemone, which includes the following transactions: + Some(vec![ + FlashTransactionV1 { + name: "anemone-validator-fee-fix".to_string(), + state_updates: generate_validator_fee_fix_state_updates(store), + } + .into(), + FlashTransactionV1 { + name: "anemone-seconds-precision".to_string(), + state_updates: generate_seconds_precision_state_updates(store), + } + .into(), + FlashTransactionV1 { + name: "anemone-vm-boot".to_string(), + state_updates: generate_vm_boot_scrypto_minor_version_state_updates(), + } + .into(), + FlashTransactionV1 { + name: "anemone-pools".to_string(), + state_updates: generate_pools_v1_1_state_updates(store), + } + .into(), + ]) + } + _ => None, + } + } +} 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 new file mode 100644 index 0000000000..d62e09c90b --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/custom_definition.rs @@ -0,0 +1,56 @@ +use crate::protocol::*; +use radix_engine::types::*; +use radix_engine_store_interface::interface::SubstateDatabase; + +/// Any protocol update beginning `custom-` can have content injected via config. +pub struct CustomProtocolUpdateDefinition; + +impl CustomProtocolUpdateDefinition { + pub const RESERVED_NAME_PREFIX: &'static str = "custom-"; + + pub fn subnamed(subname: &str) -> String { + format!("{}{}", Self::RESERVED_NAME_PREFIX, subname) + } + + pub fn matches(protocol_name: &str) -> bool { + protocol_name.starts_with(Self::RESERVED_NAME_PREFIX) + } +} + +impl ProtocolUpdateDefinition for CustomProtocolUpdateDefinition { + type Overrides = Vec>; + + fn create_updater( + new_protocol_version: &str, + network_definition: &NetworkDefinition, + overrides: Option, + ) -> Box { + Box::new(BatchedUpdater::new( + new_protocol_version.to_string(), + Self::state_computer_config(network_definition), + ArbitraryBatchGenerator { + batches: overrides.unwrap_or_default(), + }, + )) + } + + fn state_computer_config( + network_definition: &NetworkDefinition, + ) -> ProtocolStateComputerConfig { + ProtocolStateComputerConfig::default(network_definition.clone()) + } +} + +struct ArbitraryBatchGenerator { + batches: Vec>, +} + +impl UpdateBatchGenerator for ArbitraryBatchGenerator { + fn generate_batch( + &self, + _store: &impl SubstateDatabase, + batch_index: u32, + ) -> Option> { + self.batches.get(batch_index as usize).cloned() + } +} 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 new file mode 100644 index 0000000000..676938b189 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/default_definition.rs @@ -0,0 +1,22 @@ +use crate::protocol::*; +use radix_engine::types::*; + +pub struct DefaultConfigOnlyProtocolDefinition; + +impl ProtocolUpdateDefinition for DefaultConfigOnlyProtocolDefinition { + type Overrides = (); + + fn create_updater( + _new_protocol_version: &str, + _network_definition: &NetworkDefinition, + _overrides: Option, + ) -> Box { + Box::new(NoOpProtocolUpdater) + } + + fn state_computer_config( + network_definition: &NetworkDefinition, + ) -> ProtocolStateComputerConfig { + ProtocolStateComputerConfig::default(network_definition.clone()) + } +} 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 new file mode 100644 index 0000000000..b27767068e --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/mod.rs @@ -0,0 +1,9 @@ +mod anemone_definition; +mod custom_definition; +mod default_definition; +mod test_definition; + +pub use anemone_definition::*; +pub use custom_definition::*; +pub use default_definition::*; +pub use test_definition::*; 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 new file mode 100644 index 0000000000..e8c8698ed7 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/definitions/test_definition.rs @@ -0,0 +1,64 @@ +use crate::{protocol::*, transaction::FlashTransactionV1}; +use radix_engine::{track::StateUpdates, types::*}; +use radix_engine_store_interface::interface::SubstateDatabase; + +/// Any protocol update beginning `test-` just injects a single transaction. +pub struct TestProtocolUpdateDefinition; + +impl TestProtocolUpdateDefinition { + pub const RESERVED_NAME_PREFIX: &'static str = "test-"; + + pub fn subnamed(subname: &str) -> String { + format!("{}{}", Self::RESERVED_NAME_PREFIX, subname) + } + + pub fn matches(protocol_name: &str) -> bool { + protocol_name.starts_with(Self::RESERVED_NAME_PREFIX) + } +} + +impl ProtocolUpdateDefinition for TestProtocolUpdateDefinition { + type Overrides = (); + + fn create_updater( + new_protocol_version: &str, + network_definition: &NetworkDefinition, + _overrides: Option, + ) -> Box { + Box::new(BatchedUpdater::new( + new_protocol_version.to_string(), + Self::state_computer_config(network_definition), + TestBatchGenerator { + protocol_version_name: new_protocol_version.to_string(), + }, + )) + } + + fn state_computer_config( + network_definition: &NetworkDefinition, + ) -> ProtocolStateComputerConfig { + ProtocolStateComputerConfig::default(network_definition.clone()) + } +} + +struct TestBatchGenerator { + protocol_version_name: String, +} + +impl UpdateBatchGenerator for TestBatchGenerator { + fn generate_batch( + &self, + _store: &impl SubstateDatabase, + batch_index: u32, + ) -> Option> { + match batch_index { + 0 => Some(vec![UpdateTransaction::FlashTransactionV1( + FlashTransactionV1 { + name: format!("{}-txn", &self.protocol_version_name), + state_updates: StateUpdates::default(), + }, + )]), + _ => None, + } + } +} diff --git a/core-rust/state-manager/src/protocol/protocol_updates/mod.rs b/core-rust/state-manager/src/protocol/protocol_updates/mod.rs new file mode 100644 index 0000000000..0fe73f7f19 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/mod.rs @@ -0,0 +1,13 @@ +mod definitions; +mod protocol_content_overrides; +mod protocol_definition_resolver; +mod protocol_update_committer; +mod protocol_update_definition; +mod protocol_updaters; + +pub use definitions::*; +pub use protocol_content_overrides::*; +pub use protocol_definition_resolver::*; +pub use protocol_update_committer::*; +pub use protocol_update_definition::*; +pub use protocol_updaters::*; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs new file mode 100644 index 0000000000..48ee47f5f6 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs @@ -0,0 +1,81 @@ +use super::definitions::*; +use crate::protocol::*; +use radix_engine::types::scrypto_encode; +use sbor::Sbor; + +use radix_engine_common::ScryptoSbor; +use utils::prelude::*; + +type Overrides = ::Overrides; + +/// Intended to be an easy-to-use type in rust (or java) for configuring each update. +#[derive(Default, ScryptoSbor)] +pub struct ProtocolUpdateContentOverrides { + anemone: Option>, + custom: HashMap>, +} + +impl ProtocolUpdateContentOverrides { + pub fn empty() -> Self { + Default::default() + } + + pub fn with_anemone(mut self, config: Overrides) -> Self { + self.anemone = Some(config); + self + } + + pub fn with_custom( + mut self, + custom_name: &str, + config: Overrides, + ) -> Self { + if !CustomProtocolUpdateDefinition::matches(custom_name) { + panic!( + "Not an allowed custom protocol update name: {}", + custom_name + ); + } + self.custom.insert(custom_name.to_string(), config); + self + } +} + +impl From for RawProtocolUpdateContentOverrides { + fn from(value: ProtocolUpdateContentOverrides) -> Self { + let mut map = HashMap::default(); + + if let Some(config) = value.anemone { + map.insert( + ANEMONE_PROTOCOL_VERSION.to_string(), + scrypto_encode(&config).unwrap(), + ); + } + + for (update_name, config) in value.custom { + if CustomProtocolUpdateDefinition::matches(&update_name) { + map.insert(update_name, scrypto_encode(&config).unwrap()); + } + } + + Self(map) + } +} + +#[derive(Default, Clone, Debug, Eq, PartialEq, Sbor)] +#[sbor(transparent)] +pub struct RawProtocolUpdateContentOverrides(HashMap>); + +impl RawProtocolUpdateContentOverrides { + pub fn none() -> Self { + Default::default() + } + + pub fn iter(&self) -> hash_map::Iter> { + self.0.iter() + } + + pub fn get(&self, protocol_version_name: &str) -> Option<&[u8]> { + self.0.get(protocol_version_name).map(|x| x.as_ref()) + } +} diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs new file mode 100644 index 0000000000..705869e657 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs @@ -0,0 +1,103 @@ +use super::definitions::*; +use crate::protocol::*; +use sbor::DecodeError; + +use radix_engine_common::network::NetworkDefinition; +use utils::prelude::*; + +pub const GENESIS_PROTOCOL_VERSION: &str = "babylon-genesis"; +pub const ANEMONE_PROTOCOL_VERSION: &str = "anemone"; + +pub struct ProtocolDefinitionResolver { + network: NetworkDefinition, + raw_update_config: RawProtocolUpdateContentOverrides, +} + +fn resolve_update_definition_for_version( + protocol_version_name: &str, +) -> Option> { + match protocol_version_name { + // Genesis execution is done manually. + // Genesis only needs to be supported here to identify which configuration to use. + GENESIS_PROTOCOL_VERSION => Some(Box::new(DefaultConfigOnlyProtocolDefinition)), + ANEMONE_PROTOCOL_VERSION => Some(Box::new(AnemoneProtocolUpdateDefinition)), + // Updates starting "custom-" are intended for use with tests, where the thresholds and config are injected on all nodes + _ if CustomProtocolUpdateDefinition::matches(protocol_version_name) => { + Some(Box::new(CustomProtocolUpdateDefinition)) + } + _ if TestProtocolUpdateDefinition::matches(protocol_version_name) => { + Some(Box::new(TestProtocolUpdateDefinition)) + } + _ => None, + } +} + +impl ProtocolDefinitionResolver { + pub fn new(network: &NetworkDefinition) -> ProtocolDefinitionResolver { + Self::new_with_raw_overrides(network, Default::default()).unwrap() + } + + pub fn new_with_overrides( + network: &NetworkDefinition, + update_config: ProtocolUpdateContentOverrides, + ) -> Result { + Self::new_with_raw_overrides(network, update_config.into()) + } + + pub fn new_with_raw_overrides( + network: &NetworkDefinition, + update_config: RawProtocolUpdateContentOverrides, + ) -> Result { + // Validate + for (configured_version, raw_config) in update_config.iter() { + let updater_factory = resolve_update_definition_for_version(configured_version).ok_or( + ConfigValidationError::UnknownProtocolVersion(configured_version.to_string()), + )?; + + updater_factory + .validate_raw_overrides(raw_config) + .map_err(|err| { + ConfigValidationError::InvalidConfigForProtocolVersion( + configured_version.to_string(), + err, + ) + })?; + } + + // Return + Ok(ProtocolDefinitionResolver { + network: network.clone(), + raw_update_config: update_config, + }) + } + + pub fn recognizes(&self, protocol_version_name: &str) -> bool { + resolve_update_definition_for_version(protocol_version_name).is_some() + } + + pub fn resolve( + &self, + protocol_version_name: &str, + ) -> Option<(ProtocolStateComputerConfig, Box)> { + let definition = resolve_update_definition_for_version(protocol_version_name)?; + + let config = definition.resolve_state_computer_config(&self.network); + + // Unwrap is allowed because we have already validated the raw config + let updater = definition + .create_updater_with_raw_overrides( + protocol_version_name, + &self.network, + self.raw_update_config.get(protocol_version_name), + ) + .unwrap(); + + Some((config, updater)) + } +} + +#[derive(Debug)] +pub enum ConfigValidationError { + UnknownProtocolVersion(String), + InvalidConfigForProtocolVersion(String, DecodeError), +} diff --git a/core-rust/state-manager/src/protocol/protocol_update.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs similarity index 54% rename from core-rust/state-manager/src/protocol/protocol_update.rs rename to core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs index cb2ea7bb3a..dc7a71ac0e 100644 --- a/core-rust/state-manager/src/protocol/protocol_update.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs @@ -1,167 +1,30 @@ // This file contains the protocol update logic for specific protocol versions -use node_common::locks::{LockFactory, RwLock, StateLock}; -use radix_engine::track::StateUpdates; -use radix_engine::transaction::CostingParameters; -use radix_engine_common::network::NetworkDefinition; -use radix_engine_common::prelude::Decimal; use std::ops::Deref; use std::sync::Arc; -use transaction::prelude::TransactionPayloadPreparable; -use transaction::validation::{NotarizedTransactionValidator, ValidationConfig}; -use utils::btreemap; +use node_common::locks::{LockFactory, RwLock, StateLock}; +use radix_engine::prelude::*; + +use transaction::prelude::*; use crate::epoch_handling::EpochAwareAccuTreeFactory; -use crate::mainnet_updates::ProductionProtocolUpdaterFactory; -use crate::traits::{ - CommitBundle, CommitStore, CommittedTransactionBundle, HashTreeUpdate, QueryableProofStore, - ReceiptAccuTreeSliceV1, SubstateStoreUpdate, TransactionAccuTreeSliceV1, -}; -use crate::transaction::{ - ExecutionConfigurator, FlashTransactionV1, LedgerTransaction, LedgerTransactionValidator, - PreparedLedgerTransaction, TransactionSeriesExecutor, -}; +use crate::protocol::*; +use crate::traits::*; +use crate::transaction::*; use crate::{ CommittedTransactionIdentifiers, ExecutionCache, LedgerHeader, LedgerProof, LedgerProofOrigin, - LoggingConfig, ProtocolState, StateManagerDatabase, + StateManagerDatabase, }; -pub trait ProtocolUpdaterFactory { - fn updater_for(&self, protocol_version_name: &str) -> Option>; -} - -/// Protocol update consists of two events: -/// 1) Updating the current (state computer) configuration ("transaction processing rules"). -/// This includes: transaction validation, execution configuration, etc -/// 2) Executing arbitrary state updates against the current database state. -/// While the abstraction is quite flexible, the only concrete implementation at the moment -/// only modifies the state through committing system transactions (e.g. substate flash). -pub trait ProtocolUpdater { - /// Returns the new configuration that the state computer - /// should use after enacting the given protocol version. - fn updatable_config(&self) -> UpdatableStateComputerConfig; - - /// Executes these state updates associated with the given protocol version - /// that haven't yet been applied - /// (hence "remaining", e.g. if node is restarted mid-protocol update). - fn execute_remaining_state_updates(&self, store: Arc>); -} - -#[derive(Clone, Debug)] -pub struct UpdatableStateComputerConfig { - pub network: NetworkDefinition, - pub logging_config: LoggingConfig, - pub validation_config: ValidationConfig, - pub costing_parameters: CostingParameters, -} - -impl UpdatableStateComputerConfig { - pub fn default(network: NetworkDefinition) -> UpdatableStateComputerConfig { - let network_id = network.id; - UpdatableStateComputerConfig { - network, - logging_config: LoggingConfig::default(), - validation_config: ValidationConfig::default(network_id), - costing_parameters: CostingParameters::default(), - } - } -} - -impl UpdatableStateComputerConfig { - pub fn ledger_transaction_validator(&self) -> LedgerTransactionValidator { - LedgerTransactionValidator::default_from_validation_config(self.validation_config) - } - - pub fn user_transaction_validator(&self) -> NotarizedTransactionValidator { - NotarizedTransactionValidator::new(self.validation_config) - } - - pub fn validation_config(&self) -> ValidationConfig { - self.validation_config - } - - pub fn execution_configurator(&self, no_fees: bool) -> ExecutionConfigurator { - let mut costing_parameters = self.costing_parameters; - if no_fees { - costing_parameters.execution_cost_unit_price = Decimal::ZERO; - costing_parameters.finalization_cost_unit_price = Decimal::ZERO; - costing_parameters.state_storage_price = Decimal::ZERO; - costing_parameters.archive_storage_price = Decimal::ZERO; - } - ExecutionConfigurator::new(&self.network, &self.logging_config, costing_parameters) - } -} - -/// A protocol updater implementation that only changes the configuration -/// and does not commit any state updates. -pub struct NoStateUpdatesProtocolUpdater { - updatable_config: UpdatableStateComputerConfig, -} - -impl NoStateUpdatesProtocolUpdater { - pub fn default(network: NetworkDefinition) -> Self { - Self { - updatable_config: UpdatableStateComputerConfig::default(network), - } - } -} - -impl ProtocolUpdater for NoStateUpdatesProtocolUpdater { - fn updatable_config(&self) -> UpdatableStateComputerConfig { - self.updatable_config.clone() - } - - fn execute_remaining_state_updates(&self, _store: Arc>) { - // no-op - } -} - -pub struct FixedFlashProtocolUpdater { - protocol_version_name: String, - updatable_config: UpdatableStateComputerConfig, - flash_txns: Vec, -} - -impl FixedFlashProtocolUpdater { - pub fn new_with_default_configurator( - protocol_version_name: String, - network: NetworkDefinition, - flash_txns: Vec, - ) -> Self { - Self { - protocol_version_name, - updatable_config: UpdatableStateComputerConfig::default(network), - flash_txns, - } - } +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub enum UpdateTransaction { + FlashTransactionV1(FlashTransactionV1), } -impl ProtocolUpdater for FixedFlashProtocolUpdater { - fn updatable_config(&self) -> UpdatableStateComputerConfig { - self.updatable_config.clone() - } - - fn execute_remaining_state_updates(&self, store: Arc>) { - // We're using the new configuration to execute the protocol update - // transactions (although it's not a requirement). - let updatable_config = self.updatable_config(); - let mut txn_committer = ProtocolUpdateFlashTxnCommitter::new( - self.protocol_version_name.clone(), - store, - updatable_config.execution_configurator(true), /* No fees for protocol updates */ - updatable_config.ledger_transaction_validator(), - ); - - while let Some(next_batch_idx) = txn_committer.next_committable_batch_idx() { - let maybe_next_flash_txn = self.flash_txns.get(next_batch_idx as usize); - if let Some(next_flash_txn) = maybe_next_flash_txn { - txn_committer.commit_flash(next_flash_txn.clone()); - } else { - // Nothing more to commit - break; - } - } +impl From for UpdateTransaction { + fn from(value: FlashTransactionV1) -> Self { + Self::FlashTransactionV1(value) } } @@ -183,14 +46,14 @@ enum ProtocolUpdateProgress { /// A helper that manages committing flash transactions state updates. /// It handles the logic to fulfill the resumability contract of "execute_remaining_state_updates" /// by storing the index of a previously committed transaction batch in the ledger proof. -pub struct ProtocolUpdateFlashTxnCommitter { +pub struct ProtocolUpdateTransactionCommitter { protocol_version_name: String, store: Arc>, execution_configurator: RwLock, ledger_transaction_validator: LedgerTransactionValidator, } -impl ProtocolUpdateFlashTxnCommitter { +impl ProtocolUpdateTransactionCommitter { pub fn new( protocol_version_name: String, store: Arc>, @@ -259,18 +122,22 @@ impl ProtocolUpdateFlashTxnCommitter { } } - pub fn commit_flash(&mut self, flash_txn: FlashTransactionV1) { - self.commit_flash_batch(vec![flash_txn]); + pub fn commit_single(&mut self, transaction: UpdateTransaction) { + self.commit_batch(vec![transaction]); } /// Commits a batch of flash transactions, followed by a single /// proof (of protocol update origin). - pub fn commit_flash_batch(&mut self, flash_txns: Vec) { - let flash_ledger_txns = flash_txns + pub fn commit_batch(&mut self, update_transactions: Vec) { + let ledger_transactions = update_transactions .into_iter() - .map(|flash_txn| LedgerTransaction::FlashV1(Box::new(flash_txn))) + .map(|update_txn| match update_txn { + UpdateTransaction::FlashTransactionV1(flash_txn) => { + LedgerTransaction::FlashV1(Box::new(flash_txn)) + } + }) .collect(); - self.commit_txn_batch(flash_ledger_txns); + self.commit_txn_batch(ledger_transactions); } fn commit_txn_batch(&mut self, transactions: Vec) { @@ -388,36 +255,3 @@ impl ProtocolUpdateFlashTxnCommitter { self.store.write_current().commit(commit_bundle); } } - -pub struct TestingDefaultProtocolUpdaterFactory { - network: NetworkDefinition, - mainnet_protocol_updater_factory: ProductionProtocolUpdaterFactory, -} - -impl TestingDefaultProtocolUpdaterFactory { - pub fn new(network: NetworkDefinition) -> TestingDefaultProtocolUpdaterFactory { - TestingDefaultProtocolUpdaterFactory { - network: network.clone(), - mainnet_protocol_updater_factory: ProductionProtocolUpdaterFactory::new(network), - } - } -} - -impl ProtocolUpdaterFactory for TestingDefaultProtocolUpdaterFactory { - fn updater_for(&self, protocol_version_name: &str) -> Option> { - // Default testing updater delegates to mainnet updater if protocol update matches or, - // if not, returns a default updater with a single empty flash transaction. - self.mainnet_protocol_updater_factory - .updater_for(protocol_version_name) - .or(Some(Box::new( - FixedFlashProtocolUpdater::new_with_default_configurator( - protocol_version_name.to_owned(), - self.network.clone(), - vec![FlashTransactionV1 { - name: format!("{}-txn", protocol_version_name), - state_updates: StateUpdates::default(), - }], - ), - ))) - } -} 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 new file mode 100644 index 0000000000..301dfb9161 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_definition.rs @@ -0,0 +1,124 @@ +// This file contains the protocol update logic for specific protocol versions + +use crate::protocol::*; +use radix_engine::transaction::CostingParameters; +use radix_engine::types::*; + +use crate::transaction::*; +use crate::LoggingConfig; +use transaction::validation::{NotarizedTransactionValidator, ValidationConfig}; + +/// A protocol update definition consists of two parts: +/// 1) Updating the current (state computer) configuration ("transaction processing rules"). +/// This includes: transaction validation, execution configuration, etc +/// 2) Executing arbitrary state updates against the current database state. +/// While the abstraction is quite flexible, the only concrete implementation at the moment +/// only modifies the state through committing system transactions (e.g. substate flash). +pub trait ProtocolUpdateDefinition { + /// Additional (static) config which can be used to re-configure the updater. + type Overrides: ScryptoDecode; + + /// Returns the new configuration that the state computer + /// should use after enacting the given protocol version. + fn state_computer_config(network_definition: &NetworkDefinition) + -> ProtocolStateComputerConfig; + + fn create_updater( + new_protocol_version: &str, + network_definition: &NetworkDefinition, + overrides: Option, + ) -> Box; +} + +pub trait ConfigurableProtocolUpdateDefinition { + fn resolve_state_computer_config( + &self, + network_definition: &NetworkDefinition, + ) -> ProtocolStateComputerConfig; + + /// Must return `Ok` if the `raw_config` is None or passed validate. + fn create_updater_with_raw_overrides( + &self, + new_protocol_version: &str, + network_definition: &NetworkDefinition, + raw_config: Option<&[u8]>, + ) -> Result, DecodeError>; + + fn validate_raw_overrides(&self, raw_config: &[u8]) -> Result<(), DecodeError>; +} + +impl ConfigurableProtocolUpdateDefinition for T { + fn resolve_state_computer_config( + &self, + network_definition: &NetworkDefinition, + ) -> ProtocolStateComputerConfig { + Self::state_computer_config(network_definition) + } + + /// If no raw config is provided, the default config is used + fn create_updater_with_raw_overrides( + &self, + new_protocol_version: &str, + network_definition: &NetworkDefinition, + raw_overrides: Option<&[u8]>, + ) -> Result, DecodeError> { + let overrides = raw_overrides + .map(scrypto_decode::<::Overrides>) + .transpose()?; + + Ok(Self::create_updater( + new_protocol_version, + network_definition, + overrides, + )) + } + + fn validate_raw_overrides(&self, raw_config: &[u8]) -> Result<(), DecodeError> { + scrypto_decode::<::Overrides>(raw_config).map(|_| ()) + } +} + +#[derive(Clone, Debug)] +pub struct ProtocolStateComputerConfig { + pub network: NetworkDefinition, + pub logging_config: LoggingConfig, + pub validation_config: ValidationConfig, + pub costing_parameters: CostingParameters, +} + +impl ProtocolStateComputerConfig { + pub fn default(network: NetworkDefinition) -> ProtocolStateComputerConfig { + let network_id = network.id; + ProtocolStateComputerConfig { + network, + logging_config: LoggingConfig::default(), + validation_config: ValidationConfig::default(network_id), + costing_parameters: CostingParameters::default(), + } + } +} + +impl ProtocolStateComputerConfig { + pub fn ledger_transaction_validator(&self) -> LedgerTransactionValidator { + LedgerTransactionValidator::default_from_validation_config(self.validation_config) + } + + pub fn user_transaction_validator(&self) -> NotarizedTransactionValidator { + NotarizedTransactionValidator::new(self.validation_config) + } + + pub fn validation_config(&self) -> ValidationConfig { + self.validation_config + } + + pub fn execution_configurator(&self, no_fees: bool) -> ExecutionConfigurator { + let mut costing_parameters = self.costing_parameters; + if no_fees { + costing_parameters.execution_cost_unit_price = Decimal::ZERO; + costing_parameters.finalization_cost_unit_price = Decimal::ZERO; + costing_parameters.state_storage_price = Decimal::ZERO; + costing_parameters.archive_storage_price = Decimal::ZERO; + } + ExecutionConfigurator::new(&self.network, &self.logging_config, costing_parameters) + } +} diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs new file mode 100644 index 0000000000..28bd20e769 --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs @@ -0,0 +1,79 @@ +use node_common::locks::StateLock; +use std::ops::Deref; +use std::sync::Arc; + +use crate::protocol::*; +use crate::traits::*; +use crate::StateManagerDatabase; + +pub trait ProtocolUpdater { + /// Executes these state updates associated with the given protocol version + /// that haven't yet been applied + /// (hence "remaining", e.g. if node is restarted mid-protocol update). + fn execute_remaining_state_updates(&self, store: Arc>); +} + +pub struct NoOpProtocolUpdater; + +impl ProtocolUpdater for NoOpProtocolUpdater { + fn execute_remaining_state_updates(&self, _store: Arc>) { + // no-op + } +} + +pub(crate) struct BatchedUpdater { + new_protocol_version: String, + new_state_computer_config: ProtocolStateComputerConfig, + resolver: R, +} + +impl BatchedUpdater { + pub fn new( + new_protocol_version: String, + new_state_computer_config: ProtocolStateComputerConfig, + batch_generator: G, + ) -> Self { + Self { + new_protocol_version, + new_state_computer_config, + resolver: batch_generator, + } + } +} + +impl ProtocolUpdater for BatchedUpdater { + fn execute_remaining_state_updates(&self, store: Arc>) { + let mut txn_committer = ProtocolUpdateTransactionCommitter::new( + self.new_protocol_version.clone(), + store.clone(), + self.new_state_computer_config.execution_configurator(true), /* No fees for protocol updates */ + self.new_state_computer_config + .ledger_transaction_validator(), + ); + + while let Some(next_batch_idx) = txn_committer.next_committable_batch_idx() { + let batch = { + // Put it in a scope to ensure the read lock is dropped before we attempt to commit + let read_store = store.read_current(); + self.resolver + .generate_batch(read_store.deref(), next_batch_idx) + }; + match batch { + Some(flash_txns) => { + txn_committer.commit_batch(flash_txns); + } + None => break, + } + } + } +} + +pub(crate) trait UpdateBatchGenerator { + /// Generate a batch of transactions to be committed atomically with a proof. + /// Return None if it's the last batch. + fn generate_batch( + &self, + state_database: &impl SubstateDatabase, + batch_index: u32, + ) -> Option>; +} diff --git a/core-rust/state-manager/src/protocol/test.rs b/core-rust/state-manager/src/protocol/test.rs index 4e85b729e8..92422d8c31 100644 --- a/core-rust/state-manager/src/protocol/test.rs +++ b/core-rust/state-manager/src/protocol/test.rs @@ -72,7 +72,6 @@ use radix_engine::prelude::dec; use radix_engine::system::system_substates::FieldSubstate; use radix_engine::utils::generate_validator_fee_fix_state_updates; -use radix_engine_common::network::NetworkDefinition; use radix_engine_common::prelude::{Epoch, CONSENSUS_MANAGER}; use radix_engine_interface::prelude::MAIN_BASE_PARTITION; use radix_engine_store_interface::db_key_mapper::{MappedSubstateDatabase, SpreadPrefixKeyMapper}; @@ -82,41 +81,14 @@ use sbor::HasLatestVersion; use node_common::locks::LockFactory; use node_common::scheduler::Scheduler; -use crate::ProtocolUpdateEnactmentCondition::EnactUnconditionallyAtEpoch; -use crate::{ - FixedFlashProtocolUpdater, NoStateUpdatesProtocolUpdater, ProtocolConfig, ProtocolUpdate, - ProtocolUpdater, ProtocolUpdaterFactory, StateManager, StateManagerConfig, -}; -use radix_engine::track::StateUpdates; +use crate::protocol::*; +use crate::{StateManager, StateManagerConfig}; use std::ops::Deref; use crate::test::prepare_and_commit_round_update; use crate::transaction::FlashTransactionV1; -const GENESIS_PROTOCOL_VERSION: &str = "testing-genesis"; -const V2_PROTOCOL_VERSION: &str = "testing-v2"; - -struct TestProtocolUpdaterFactory { - v2_flash: FlashTransactionV1, -} - -impl ProtocolUpdaterFactory for TestProtocolUpdaterFactory { - fn updater_for(&self, protocol_version_name: &str) -> Option> { - match protocol_version_name { - GENESIS_PROTOCOL_VERSION => Some(Box::new(NoStateUpdatesProtocolUpdater::default( - NetworkDefinition::simulator(), - ))), - V2_PROTOCOL_VERSION => Some(Box::new( - FixedFlashProtocolUpdater::new_with_default_configurator( - V2_PROTOCOL_VERSION.to_string(), - NetworkDefinition::simulator(), - vec![self.v2_flash.clone()], - ), - )), - _ => None, - } - } -} +const CUSTOM_V2_PROTOCOL_VERSION: &str = "custom-v2"; #[test] fn flash_protocol_update_test() { @@ -126,28 +98,23 @@ fn flash_protocol_update_test() { // We're enacting an update after another transaction commit let protocol_update_epoch = Epoch::of(3); - // Updating to "testing-v2" at post_genesis_state_version + 1 state_manager_config.protocol_config = ProtocolConfig { genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), - protocol_updates: vec![ProtocolUpdate { - next_protocol_version: V2_PROTOCOL_VERSION.to_string(), - enactment_condition: EnactUnconditionallyAtEpoch(protocol_update_epoch), + protocol_update_triggers: vec![ProtocolUpdateTrigger { + next_protocol_version: CUSTOM_V2_PROTOCOL_VERSION.to_string(), + enactment_condition: + ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally( + protocol_update_epoch, + ), }], + // This is temporary - we will generate the custom state updates below + protocol_update_content_overrides: RawProtocolUpdateContentOverrides::none(), }; // This is a bit of a hack to be able to use fixed flash protocol update let consensus_manager_state_updates = { // Run the genesis first - let tmp_state_manager = create_state_manager( - state_manager_config.clone(), - // Fake updater, unused - Box::new(TestProtocolUpdaterFactory { - v2_flash: FlashTransactionV1 { - name: "unused".to_string(), - state_updates: StateUpdates::default(), - }, - }), - ); + let tmp_state_manager = create_state_manager(state_manager_config.clone()); tmp_state_manager .state_computer .execute_genesis_for_unit_tests_with_default_config(); @@ -158,15 +125,20 @@ fn flash_protocol_update_test() { state_updates }; - let state_manager = create_state_manager( - state_manager_config, - Box::new(TestProtocolUpdaterFactory { - v2_flash: FlashTransactionV1 { - name: "testing-v2-flash".to_string(), + state_manager_config + .protocol_config + .protocol_update_content_overrides = ProtocolUpdateContentOverrides::empty() + .with_custom( + CUSTOM_V2_PROTOCOL_VERSION, + vec![vec![FlashTransactionV1 { + name: format!("{CUSTOM_V2_PROTOCOL_VERSION}-flash"), state_updates: consensus_manager_state_updates, - }, - }), - ); + } + .into()]], + ) + .into(); + + let state_manager = create_state_manager(state_manager_config); // Commit 3 round updates to get us to the next epoch (3). let _ = prepare_and_commit_round_update(&state_manager); @@ -180,18 +152,24 @@ fn flash_protocol_update_test() { assert_eq!( prepare_result.next_protocol_version, - Some(V2_PROTOCOL_VERSION.to_string()) + Some(CUSTOM_V2_PROTOCOL_VERSION.to_string()) ); - let read_db = state_manager.database.read_current(); - let pre_protocol_update_state_version = read_db.max_state_version(); - drop(read_db); + let pre_protocol_update_state_version = + state_manager.database.read_current().max_state_version(); // Now let's apply the protocol update (this would normally be called by Java) - state_manager.apply_protocol_update(V2_PROTOCOL_VERSION); + state_manager.apply_protocol_update(CUSTOM_V2_PROTOCOL_VERSION); - // Verify that a new consensus manager config has been flashed let read_db = state_manager.database.read_current(); + + // Verify a transaction has been committed + assert_eq!( + read_db.max_state_version(), + pre_protocol_update_state_version.next().unwrap() + ); + + // Verify that a new consensus manager config has been flashed let config_substate = read_db.get_mapped::>( CONSENSUS_MANAGER.as_node_id(), MAIN_BASE_PARTITION, @@ -206,22 +184,13 @@ fn flash_protocol_update_test() { .validator_creation_usd_cost, dec!("100") ); - - assert_eq!( - read_db.max_state_version(), - pre_protocol_update_state_version.next().unwrap() - ); } -fn create_state_manager( - config: StateManagerConfig, - protocol_updater_factory: Box, -) -> StateManager { +fn create_state_manager(config: StateManagerConfig) -> StateManager { StateManager::new( config, None, &LockFactory::new("testing"), - protocol_updater_factory, &Registry::new(), &Scheduler::new("testing"), ) diff --git a/core-rust/state-manager/src/staging/cache.rs b/core-rust/state-manager/src/staging/cache.rs index 48b4cad747..c074ae80a0 100644 --- a/core-rust/state-manager/src/staging/cache.rs +++ b/core-rust/state-manager/src/staging/cache.rs @@ -68,13 +68,12 @@ use super::stage_tree::{Accumulator, Delta, DerivedStageKey, StageKey, StageTree use super::ReadableStore; use crate::accumulator_tree::storage::{ReadableAccuTreeStore, TreeSlice}; +use crate::protocol::ProtocolState; use crate::staging::{ AccuTreeDiff, HashStructuresDiff, HashUpdateContext, ProcessedTransactionReceipt, StateHashTreeDiff, }; -use crate::{ - EpochTransactionIdentifiers, ProtocolState, ReceiptTreeHash, StateVersion, TransactionTreeHash, -}; +use crate::{EpochTransactionIdentifiers, ReceiptTreeHash, StateVersion, TransactionTreeHash}; use im::hashmap::HashMap as ImmutableHashMap; use itertools::Itertools; diff --git a/core-rust/state-manager/src/staging/result.rs b/core-rust/state-manager/src/staging/result.rs index 04561db572..e5fb2f3a23 100644 --- a/core-rust/state-manager/src/staging/result.rs +++ b/core-rust/state-manager/src/staging/result.rs @@ -65,12 +65,13 @@ use super::ReadableStateTreeStore; use crate::accumulator_tree::storage::{ReadableAccuTreeStore, TreeSlice, WriteableAccuTreeStore}; +use crate::protocol::ProtocolState; use crate::staging::epoch_handling::EpochAwareAccuTreeFactory; use crate::transaction::LedgerTransactionHash; use crate::{ ActiveValidatorInfo, ByPartition, BySubstate, DetailedTransactionOutcome, EpochTransactionIdentifiers, LedgerHashes, LedgerStateChanges, LocalTransactionReceipt, - NextEpoch, PartitionChangeAction, ProtocolState, ReceiptTreeHash, StateHash, StateVersion, + NextEpoch, PartitionChangeAction, ReceiptTreeHash, StateHash, StateVersion, SubstateChangeAction, SubstateReference, TransactionTreeHash, }; use radix_engine::blueprints::consensus_manager::EpochChangeEvent; diff --git a/core-rust/state-manager/src/state_computer.rs b/core-rust/state-manager/src/state_computer.rs index 77d86123e0..a8c4004b6b 100644 --- a/core-rust/state-manager/src/state_computer.rs +++ b/core-rust/state-manager/src/state_computer.rs @@ -89,6 +89,7 @@ use node_common::locks::{LockFactory, Mutex, RwLock, StateLock}; use prometheus::Registry; use tracing::{debug, info, warn}; +use crate::protocol::*; use crate::store::traits::scenario::{ DescribedAddress, ExecutedGenesisScenario, ExecutedGenesisScenarioStore, ExecutedScenarioTransaction, ScenarioSequenceNumber, @@ -133,7 +134,7 @@ impl< pending_transaction_result_cache: Arc>, metrics_registry: &Registry, lock_factory: LockFactory, - initial_updatable_config: &UpdatableStateComputerConfig, + initial_updatable_config: &ProtocolStateComputerConfig, initial_protocol_state: ProtocolState, ) -> StateComputer { let (current_transaction_root, current_ledger_proposer_timestamp_ms) = store @@ -1418,7 +1419,6 @@ mod tests { use std::ops::Deref; use crate::transaction::{LedgerTransaction, RoundUpdateTransactionV1}; - use crate::TestingDefaultProtocolUpdaterFactory; use crate::{ LedgerProof, PrepareRequest, PrepareResult, RoundHistory, StateManager, StateManagerConfig, }; @@ -1533,9 +1533,6 @@ mod tests { config, None, &lock_factory, - Box::new(TestingDefaultProtocolUpdaterFactory::new( - NetworkDefinition::simulator(), - )), &metrics_registry, &Scheduler::new("testing"), ); diff --git a/core-rust/state-manager/src/state_manager.rs b/core-rust/state-manager/src/state_manager.rs index a87c32ee7d..7ecb6f7d38 100644 --- a/core-rust/state-manager/src/state_manager.rs +++ b/core-rust/state-manager/src/state_manager.rs @@ -76,6 +76,7 @@ use prometheus::Registry; use radix_engine_common::prelude::*; use crate::jni::LedgerSyncLimitsConfig; +use crate::protocol::{ProtocolConfig, ProtocolDefinitionResolver, ProtocolState}; use crate::store::jmt_gc::StateHashTreeGcConfig; use crate::store::proofs_gc::{LedgerProofsGc, LedgerProofsGcConfig}; use crate::store::traits::proofs::QueryableProofStore; @@ -89,8 +90,7 @@ use crate::{ StateManagerDatabase, }, transaction::{CachedCommittabilityValidator, CommittabilityValidator, TransactionPreviewer}, - PendingTransactionResultCache, ProtocolConfig, ProtocolState, ProtocolUpdateResult, - ProtocolUpdaterFactory, StateComputer, + PendingTransactionResultCache, ProtocolUpdateResult, StateComputer, }; /// An interval between time-intensive measurement of raw DB metrics. @@ -115,7 +115,7 @@ pub struct StateManagerConfig { pub no_fees: bool, } -#[derive(Debug, Categorize, Encode, Decode, Clone, Default)] +#[derive(Debug, Clone, Default, Sbor)] pub struct LoggingConfig { pub engine_trace: bool, } @@ -134,7 +134,7 @@ impl StateManagerConfig { state_hash_tree_gc_config: StateHashTreeGcConfig::default(), ledger_proofs_gc_config: LedgerProofsGcConfig::default(), ledger_sync_limits_config: LedgerSyncLimitsConfig::default(), - protocol_config: ProtocolConfig::no_updates("testing-genesis".to_string()), + protocol_config: ProtocolConfig::new_with_no_updates(), no_fees: false, } } @@ -151,7 +151,7 @@ pub struct StateManager { pub execution_configurator: Arc>, pub committability_validator: Arc>>, pub transaction_previewer: Arc>>, - pub protocol_updater_factory: Arc, + pub protocol_definition_resolver: Arc, } impl StateManager { @@ -165,19 +165,12 @@ impl StateManager { config: StateManagerConfig, mempool_relay_dispatcher: Option, lock_factory: &LockFactory, - protocol_updater_factory: Box, metrics_registry: &Registry, scheduler: &Scheduler, ) -> Self { - let mempool_config = match config.mempool_config.clone() { - Some(mempool_config) => mempool_config, - None => - // in general, missing mempool config should mean that mempool isn't needed - // but for now just using a default - { - MempoolConfig::default() - } - }; + // in general, missing mempool config should mean that mempool isn't needed + // but for now just using a default + let mempool_config = config.mempool_config.clone().unwrap_or_default(); let network = config.network_definition.clone(); let _logging_config = config.logging_config.clone(); @@ -188,10 +181,18 @@ impl StateManager { ); let database = Arc::new(lock_factory.named("database").new_state_lock(raw_db)); + let protocol_definition_resolver = ProtocolDefinitionResolver::new_with_raw_overrides( + &network, + config + .protocol_config + .protocol_update_content_overrides + .clone(), + ) + .unwrap_or_else(|err| panic!("Invalid protocol update content overrides: {:?}", err)); if let Err(err) = config .protocol_config - .sanity_check(protocol_updater_factory.deref()) + .validate(&protocol_definition_resolver) { panic!("Protocol misconfiguration: {}", err); }; @@ -201,15 +202,21 @@ impl StateManager { &config.protocol_config, ); - let initial_protocol_updater = protocol_updater_factory - .updater_for(&initial_protocol_state.current_protocol_version) - .expect("Protocol updater is misconfigured"); - let initial_updatable_config = initial_protocol_updater.updatable_config(); + let initial_protocol_version = &initial_protocol_state.current_protocol_version; + let (initial_state_computer_config, initial_protocol_updater) = + protocol_definition_resolver + .resolve(initial_protocol_version) + .unwrap_or_else(|| { + panic!( + "Initial protocol version on boot ({}) was not known in the resolver", + initial_protocol_version + ) + }); let execution_configurator = Arc::new( lock_factory .named("execution_configurator") - .new_rwlock(initial_updatable_config.execution_configurator(config.no_fees)), + .new_rwlock(initial_state_computer_config.execution_configurator(config.no_fees)), ); let pending_transaction_result_cache = Arc::new( @@ -222,7 +229,7 @@ impl StateManager { CommittabilityValidator::new( database.clone(), execution_configurator.clone(), - initial_updatable_config.user_transaction_validator(), + initial_state_computer_config.user_transaction_validator(), ), )); let cached_committability_validator = CachedCommittabilityValidator::new( @@ -256,7 +263,7 @@ impl StateManager { TransactionPreviewer::new( database.clone(), execution_configurator.clone(), - initial_updatable_config.validation_config(), + initial_state_computer_config.validation_config(), ), )); @@ -279,7 +286,7 @@ impl StateManager { pending_transaction_result_cache.clone(), metrics_registry, lock_factory.named("state_computer"), - &initial_updatable_config, + &initial_state_computer_config, initial_protocol_state, )); @@ -324,39 +331,42 @@ impl StateManager { execution_configurator, committability_validator, transaction_previewer, - protocol_updater_factory: protocol_updater_factory.into(), + protocol_definition_resolver: Arc::new(protocol_definition_resolver), } } pub fn apply_protocol_update(&self, protocol_version_name: &str) -> ProtocolUpdateResult { - let protocol_updater = self - .protocol_updater_factory - .updater_for(protocol_version_name) - .expect("Protocol updater is misconfigured"); - let new_updatable_config = protocol_updater.updatable_config(); + let (new_state_computer_config, protocol_updater) = self + .protocol_definition_resolver + .resolve(protocol_version_name) + .unwrap_or_else(|| { + panic!( + "Protocol update to version {} was triggered, but isn't known in the resolver", + protocol_version_name + ) + }); let new_execution_configurator = - new_updatable_config.execution_configurator(self.config.no_fees); + new_state_computer_config.execution_configurator(self.config.no_fees); *self.execution_configurator.write() = new_execution_configurator; *self.committability_validator.write() = CommittabilityValidator::new( self.database.clone(), self.execution_configurator.clone(), - new_updatable_config.user_transaction_validator(), + new_state_computer_config.user_transaction_validator(), ); *self.transaction_previewer.write() = TransactionPreviewer::new( self.database.clone(), self.execution_configurator.clone(), - new_updatable_config.validation_config(), + new_state_computer_config.validation_config(), ); - protocol_updater.execute_remaining_state_updates(self.database.clone()); self.state_computer.handle_protocol_update( protocol_version_name, - new_updatable_config.ledger_transaction_validator(), + new_state_computer_config.ledger_transaction_validator(), ); ProtocolUpdateResult { @@ -371,7 +381,7 @@ impl StateManager { pub fn newest_protocol_version(&self) -> String { let protocol_config = &self.config.protocol_config; protocol_config - .protocol_updates + .protocol_update_triggers .last() .map(|protocol_update| protocol_update.next_protocol_version.clone()) .unwrap_or(protocol_config.genesis_protocol_version.clone()) diff --git a/core-rust/state-manager/src/store/proofs_gc.rs b/core-rust/state-manager/src/store/proofs_gc.rs index b39054a3b1..0d0228f5ad 100644 --- a/core-rust/state-manager/src/store/proofs_gc.rs +++ b/core-rust/state-manager/src/store/proofs_gc.rs @@ -314,19 +314,15 @@ impl ProofPruneRange { mod tests { use crate::jni::LedgerSyncLimitsConfig; use crate::proofs_gc::{LedgerProofsGc, LedgerProofsGcConfig}; + use crate::protocol::*; use crate::store::traits::proofs::QueryableProofStore; use crate::test::commit_round_updates_until_epoch; use crate::traits::GetSyncableTxnsAndProofError; - use crate::ProtocolUpdateEnactmentCondition::EnactUnconditionallyAtEpoch; - use crate::{ - ProtocolConfig, ProtocolUpdate, StateManager, StateManagerConfig, StateVersion, - TestingDefaultProtocolUpdaterFactory, - }; + use crate::{StateManager, StateManagerConfig, StateVersion}; use node_common::locks::LockFactory; use node_common::scheduler::Scheduler; use prometheus::Registry; - use radix_engine_common::prelude::{Decimal, NetworkDefinition}; - use radix_engine_common::types::Epoch; + use radix_engine_common::prelude::*; use radix_engine_interface::blueprints::consensus_manager::{ ConsensusManagerConfig, EpochChangeCondition, }; @@ -345,19 +341,20 @@ mod tests { }; // An unconditional protocol update at epoch 5 config.protocol_config = ProtocolConfig { - genesis_protocol_version: "testing-genesis".to_string(), - protocol_updates: vec![ProtocolUpdate { - next_protocol_version: "testing-v2".to_string(), - enactment_condition: EnactUnconditionallyAtEpoch(Epoch::of(5)), + genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), + protocol_update_triggers: vec![ProtocolUpdateTrigger { + next_protocol_version: TestProtocolUpdateDefinition::subnamed("v2"), + enactment_condition: + ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally(Epoch::of( + 5, + )), }], + protocol_update_content_overrides: ProtocolUpdateContentOverrides::empty().into(), }; let state_manager = StateManager::new( config, None, &lock_factory, - Box::new(TestingDefaultProtocolUpdaterFactory::new( - NetworkDefinition::simulator(), - )), &metrics_registry, &Scheduler::new("testing"), ); diff --git a/core-rust/state-manager/src/transaction/ledger_transaction.rs b/core-rust/state-manager/src/transaction/ledger_transaction.rs index 926755f39b..0770cd7198 100644 --- a/core-rust/state-manager/src/transaction/ledger_transaction.rs +++ b/core-rust/state-manager/src/transaction/ledger_transaction.rs @@ -128,7 +128,7 @@ pub enum GenesisTransaction { const GENESIS_TRANSACTION_FLASH_DISCRIMINATOR: u8 = 0; const GENESIS_TRANSACTION_SYSTEM_TRANSACTION_DISCRIMINATOR: u8 = 1; -#[derive(Debug, Clone, PartialEq, Eq, ManifestCategorize, ManifestEncode, ManifestDecode)] +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] pub struct FlashTransactionV1 { pub name: String, pub state_updates: StateUpdates, diff --git a/core-rust/state-manager/src/transaction/preview.rs b/core-rust/state-manager/src/transaction/preview.rs index 5716ba6d02..7aace47232 100644 --- a/core-rust/state-manager/src/transaction/preview.rs +++ b/core-rust/state-manager/src/transaction/preview.rs @@ -132,13 +132,10 @@ impl Trans #[cfg(test)] mod tests { - use crate::{ - PreviewRequest, StateManager, StateManagerConfig, TestingDefaultProtocolUpdaterFactory, - }; + use crate::{PreviewRequest, StateManager, StateManagerConfig}; use node_common::locks::LockFactory; use node_common::scheduler::Scheduler; use prometheus::Registry; - use radix_engine_common::prelude::NetworkDefinition; use transaction::builder::ManifestBuilder; use transaction::model::{MessageV1, PreviewFlags}; @@ -151,9 +148,6 @@ mod tests { StateManagerConfig::new_for_testing(tmp.path().to_str().unwrap()), None, &lock_factory, - Box::new(TestingDefaultProtocolUpdaterFactory::new( - NetworkDefinition::simulator(), - )), &metrics_registry, &Scheduler::new("testing"), ); diff --git a/core-rust/state-manager/src/transaction/series_execution.rs b/core-rust/state-manager/src/transaction/series_execution.rs index 1aabe75a84..fa2732b625 100644 --- a/core-rust/state-manager/src/transaction/series_execution.rs +++ b/core-rust/state-manager/src/transaction/series_execution.rs @@ -64,6 +64,7 @@ use std::fmt::Formatter; +use crate::protocol::*; use crate::query::*; use crate::staging::{ExecutionCache, ReadableStore}; use crate::store::traits::*; diff --git a/core/src/main/java/com/radixdlt/RadixNodeModule.java b/core/src/main/java/com/radixdlt/RadixNodeModule.java index 3a8f342de2..67d6b11772 100644 --- a/core/src/main/java/com/radixdlt/RadixNodeModule.java +++ b/core/src/main/java/com/radixdlt/RadixNodeModule.java @@ -65,7 +65,6 @@ package com.radixdlt; import com.google.common.base.Preconditions; -import com.google.common.reflect.TypeToken; import com.google.inject.AbstractModule; import com.radixdlt.addressing.Addressing; import com.radixdlt.api.CoreApiServerModule; @@ -95,8 +94,8 @@ import com.radixdlt.p2p.capability.Capabilities; import com.radixdlt.p2p.capability.LedgerSyncCapability; import com.radixdlt.protocol.ProtocolConfig; +import com.radixdlt.rev2.NetworkDefinition; import com.radixdlt.rev2.modules.*; -import com.radixdlt.sbor.NodeSborCodecs; import com.radixdlt.store.NodeStorageLocationFromPropertiesModule; import com.radixdlt.sync.SyncRelayConfig; import com.radixdlt.transaction.LedgerSyncLimitsConfig; @@ -355,17 +354,15 @@ protected void configure() { // this is tied to the number of actually-persisted proofs, and should not be configureable: var ledgerSyncLimitsConfig = LedgerSyncLimitsConfig.defaults(); + // Can be generated by ProtocolConfigGeneratorTest. final var customProtocolConfig = properties.get("protocol.custom_config", ""); final ProtocolConfig protocolConfig; if (!customProtocolConfig.isEmpty()) { protocolConfig = - NodeSborCodecs.decode( - Hex.decode(customProtocolConfig), NodeSborCodecs.resolveCodec(new TypeToken<>() {})); - } else if (network.getId() == Network.MAINNET.getId()) { - protocolConfig = ProtocolConfig.mainnet(); + ProtocolConfig.sborDecodeWithFallbackForOldVersions(Hex.decode(customProtocolConfig)); } else { - protocolConfig = ProtocolConfig.testingDefault(); + protocolConfig = ProtocolConfig.resolveForNetwork(NetworkDefinition.from(network)); } install( diff --git a/core/src/main/java/com/radixdlt/api/system/SystemModelMapper.java b/core/src/main/java/com/radixdlt/api/system/SystemModelMapper.java index 55f559ea95..257ed55613 100644 --- a/core/src/main/java/com/radixdlt/api/system/SystemModelMapper.java +++ b/core/src/main/java/com/radixdlt/api/system/SystemModelMapper.java @@ -182,7 +182,7 @@ public ProtocolConfiguration protocolConfiguration( return new ProtocolConfiguration() .genesisProtocolVersion(protocolConfig.genesisProtocolVersion()) .protocolUpdates( - protocolConfig.protocolUpdates().stream() + protocolConfig.protocolUpdateTriggers().stream() .map( protocolUpdate -> new ProtocolUpdate() @@ -196,8 +196,8 @@ private ProtocolUpdateEnactmentCondition enactmentCondition( com.radixdlt.protocol.ProtocolUpdateEnactmentCondition enactmentCondition) { return switch (enactmentCondition) { case com.radixdlt.protocol.ProtocolUpdateEnactmentCondition - .EnactAtStartOfAnEpochIfSupportedAndWithinBounds - condition -> new EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition() + .EnactAtStartOfEpochIfValidatorsReady + condition -> new EnactAtStartOfEpochIfValidatorsReadyCondition() .lowerBoundEpochInclusive(condition.lowerBoundInclusive().toLong()) .upperBoundEpochExclusive(condition.upperBoundExclusive().toLong()) .readinessThresholds( @@ -210,12 +210,11 @@ private ProtocolUpdateEnactmentCondition enactmentCondition( .requiredConsecutiveCompletedEpochsOfSupport( threshold.requiredConsecutiveCompletedEpochsOfSupport().toLong())) .toList()) - .type( - ProtocolUpdateEnactmentConditionType.ENACTATSTARTOFANEPOCHIFSUPPORTEDANDWITHINBOUNDS); - case com.radixdlt.protocol.ProtocolUpdateEnactmentCondition.EnactUnconditionallyAtEpoch - enactUnconditionallyAtEpoch -> new EnactUnconditionallyAtEpochCondition() + .type(ProtocolUpdateEnactmentConditionType.ENACTATSTARTOFEPOCHIFVALIDATORSREADY); + case com.radixdlt.protocol.ProtocolUpdateEnactmentCondition.EnactAtStartOfEpochUnconditionally + enactUnconditionallyAtEpoch -> new EnactAtStartOfEpochUnconditionallyCondition() .epoch(enactUnconditionallyAtEpoch.epoch().toLong()) - .type(ProtocolUpdateEnactmentConditionType.ENACTUNCONDITIONALLYATEPOCH); + .type(ProtocolUpdateEnactmentConditionType.ENACTATSTARTOFEPOCHUNCONDITIONALLY); }; } } diff --git a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.java b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochIfValidatorsReadyCondition.java similarity index 69% rename from core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.java rename to core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochIfValidatorsReadyCondition.java index 5e7bb19945..8c4337b5e8 100644 --- a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.java +++ b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochIfValidatorsReadyCondition.java @@ -24,9 +24,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; -import com.radixdlt.api.system.generated.models.EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition; -import com.radixdlt.api.system.generated.models.EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf; -import com.radixdlt.api.system.generated.models.EnactUnconditionallyAtEpochCondition; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochIfValidatorsReadyCondition; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochIfValidatorsReadyConditionAllOf; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochUnconditionallyCondition; import com.radixdlt.api.system.generated.models.ProtocolUpdateEnactmentCondition; import com.radixdlt.api.system.generated.models.ProtocolUpdateEnactmentConditionType; import com.radixdlt.api.system.generated.models.SignalledReadinessThreshold; @@ -39,21 +39,21 @@ import com.radixdlt.api.common.JSON; /** - * EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition + * EnactAtStartOfEpochIfValidatorsReadyCondition */ @JsonPropertyOrder({ - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.JSON_PROPERTY_LOWER_BOUND_EPOCH_INCLUSIVE, - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.JSON_PROPERTY_UPPER_BOUND_EPOCH_EXCLUSIVE, - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.JSON_PROPERTY_READINESS_THRESHOLDS + EnactAtStartOfEpochIfValidatorsReadyCondition.JSON_PROPERTY_LOWER_BOUND_EPOCH_INCLUSIVE, + EnactAtStartOfEpochIfValidatorsReadyCondition.JSON_PROPERTY_UPPER_BOUND_EPOCH_EXCLUSIVE, + EnactAtStartOfEpochIfValidatorsReadyCondition.JSON_PROPERTY_READINESS_THRESHOLDS }) @javax.annotation.processing.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class, name = "EnactAtStartOfAnEpochIfSupportedAndWithinBounds"), - @JsonSubTypes.Type(value = EnactUnconditionallyAtEpochCondition.class, name = "EnactUnconditionallyAtEpoch"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochIfValidatorsReadyCondition.class, name = "EnactAtStartOfEpochIfValidatorsReady"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochUnconditionallyCondition.class, name = "EnactAtStartOfEpochUnconditionally"), }) -public class EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition extends ProtocolUpdateEnactmentCondition { +public class EnactAtStartOfEpochIfValidatorsReadyCondition extends ProtocolUpdateEnactmentCondition { public static final String JSON_PROPERTY_LOWER_BOUND_EPOCH_INCLUSIVE = "lower_bound_epoch_inclusive"; private Long lowerBoundEpochInclusive; @@ -64,7 +64,7 @@ public class EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition extends Pr private List readinessThresholds = null; - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition lowerBoundEpochInclusive(Long lowerBoundEpochInclusive) { + public EnactAtStartOfEpochIfValidatorsReadyCondition lowerBoundEpochInclusive(Long lowerBoundEpochInclusive) { this.lowerBoundEpochInclusive = lowerBoundEpochInclusive; return this; } @@ -90,7 +90,7 @@ public void setLowerBoundEpochInclusive(Long lowerBoundEpochInclusive) { } - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition upperBoundEpochExclusive(Long upperBoundEpochExclusive) { + public EnactAtStartOfEpochIfValidatorsReadyCondition upperBoundEpochExclusive(Long upperBoundEpochExclusive) { this.upperBoundEpochExclusive = upperBoundEpochExclusive; return this; } @@ -116,12 +116,12 @@ public void setUpperBoundEpochExclusive(Long upperBoundEpochExclusive) { } - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition readinessThresholds(List readinessThresholds) { + public EnactAtStartOfEpochIfValidatorsReadyCondition readinessThresholds(List readinessThresholds) { this.readinessThresholds = readinessThresholds; return this; } - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition addReadinessThresholdsItem(SignalledReadinessThreshold readinessThresholdsItem) { + public EnactAtStartOfEpochIfValidatorsReadyCondition addReadinessThresholdsItem(SignalledReadinessThreshold readinessThresholdsItem) { if (this.readinessThresholds == null) { this.readinessThresholds = new ArrayList<>(); } @@ -151,7 +151,7 @@ public void setReadinessThresholds(List readinessTh /** - * Return true if this EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition object is equal to o. + * Return true if this EnactAtStartOfEpochIfValidatorsReadyCondition object is equal to o. */ @Override public boolean equals(Object o) { @@ -161,10 +161,10 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition enactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition = (EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition) o; - return Objects.equals(this.lowerBoundEpochInclusive, enactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.lowerBoundEpochInclusive) && - Objects.equals(this.upperBoundEpochExclusive, enactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.upperBoundEpochExclusive) && - Objects.equals(this.readinessThresholds, enactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.readinessThresholds) && + EnactAtStartOfEpochIfValidatorsReadyCondition enactAtStartOfEpochIfValidatorsReadyCondition = (EnactAtStartOfEpochIfValidatorsReadyCondition) o; + return Objects.equals(this.lowerBoundEpochInclusive, enactAtStartOfEpochIfValidatorsReadyCondition.lowerBoundEpochInclusive) && + Objects.equals(this.upperBoundEpochExclusive, enactAtStartOfEpochIfValidatorsReadyCondition.upperBoundEpochExclusive) && + Objects.equals(this.readinessThresholds, enactAtStartOfEpochIfValidatorsReadyCondition.readinessThresholds) && super.equals(o); } @@ -176,7 +176,7 @@ public int hashCode() { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("class EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition {\n"); + sb.append("class EnactAtStartOfEpochIfValidatorsReadyCondition {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); sb.append(" lowerBoundEpochInclusive: ").append(toIndentedString(lowerBoundEpochInclusive)).append("\n"); sb.append(" upperBoundEpochExclusive: ").append(toIndentedString(upperBoundEpochExclusive)).append("\n"); @@ -199,10 +199,10 @@ private String toIndentedString(Object o) { static { // Initialize and register the discriminator mappings. Map> mappings = new HashMap>(); - mappings.put("EnactAtStartOfAnEpochIfSupportedAndWithinBounds", EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class); - mappings.put("EnactUnconditionallyAtEpoch", EnactUnconditionallyAtEpochCondition.class); - mappings.put("EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition", EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class); - JSON.registerDiscriminator(EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class, "type", mappings); + mappings.put("EnactAtStartOfEpochIfValidatorsReady", EnactAtStartOfEpochIfValidatorsReadyCondition.class); + mappings.put("EnactAtStartOfEpochUnconditionally", EnactAtStartOfEpochUnconditionallyCondition.class); + mappings.put("EnactAtStartOfEpochIfValidatorsReadyCondition", EnactAtStartOfEpochIfValidatorsReadyCondition.class); + JSON.registerDiscriminator(EnactAtStartOfEpochIfValidatorsReadyCondition.class, "type", mappings); } } diff --git a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.java b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.java similarity index 76% rename from core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.java rename to core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.java index 5a6ab31f92..65fc8a5653 100644 --- a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.java +++ b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.java @@ -31,15 +31,15 @@ /** - * EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf + * EnactAtStartOfEpochIfValidatorsReadyConditionAllOf */ @JsonPropertyOrder({ - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.JSON_PROPERTY_LOWER_BOUND_EPOCH_INCLUSIVE, - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.JSON_PROPERTY_UPPER_BOUND_EPOCH_EXCLUSIVE, - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.JSON_PROPERTY_READINESS_THRESHOLDS + EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.JSON_PROPERTY_LOWER_BOUND_EPOCH_INCLUSIVE, + EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.JSON_PROPERTY_UPPER_BOUND_EPOCH_EXCLUSIVE, + EnactAtStartOfEpochIfValidatorsReadyConditionAllOf.JSON_PROPERTY_READINESS_THRESHOLDS }) @javax.annotation.processing.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") -public class EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf { +public class EnactAtStartOfEpochIfValidatorsReadyConditionAllOf { public static final String JSON_PROPERTY_LOWER_BOUND_EPOCH_INCLUSIVE = "lower_bound_epoch_inclusive"; private Long lowerBoundEpochInclusive; @@ -50,7 +50,7 @@ public class EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf { private List readinessThresholds = null; - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf lowerBoundEpochInclusive(Long lowerBoundEpochInclusive) { + public EnactAtStartOfEpochIfValidatorsReadyConditionAllOf lowerBoundEpochInclusive(Long lowerBoundEpochInclusive) { this.lowerBoundEpochInclusive = lowerBoundEpochInclusive; return this; } @@ -76,7 +76,7 @@ public void setLowerBoundEpochInclusive(Long lowerBoundEpochInclusive) { } - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf upperBoundEpochExclusive(Long upperBoundEpochExclusive) { + public EnactAtStartOfEpochIfValidatorsReadyConditionAllOf upperBoundEpochExclusive(Long upperBoundEpochExclusive) { this.upperBoundEpochExclusive = upperBoundEpochExclusive; return this; } @@ -102,12 +102,12 @@ public void setUpperBoundEpochExclusive(Long upperBoundEpochExclusive) { } - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf readinessThresholds(List readinessThresholds) { + public EnactAtStartOfEpochIfValidatorsReadyConditionAllOf readinessThresholds(List readinessThresholds) { this.readinessThresholds = readinessThresholds; return this; } - public EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf addReadinessThresholdsItem(SignalledReadinessThreshold readinessThresholdsItem) { + public EnactAtStartOfEpochIfValidatorsReadyConditionAllOf addReadinessThresholdsItem(SignalledReadinessThreshold readinessThresholdsItem) { if (this.readinessThresholds == null) { this.readinessThresholds = new ArrayList<>(); } @@ -137,7 +137,7 @@ public void setReadinessThresholds(List readinessTh /** - * Return true if this EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition_allOf object is equal to o. + * Return true if this EnactAtStartOfEpochIfValidatorsReadyCondition_allOf object is equal to o. */ @Override public boolean equals(Object o) { @@ -147,10 +147,10 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf enactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf = (EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf) o; - return Objects.equals(this.lowerBoundEpochInclusive, enactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.lowerBoundEpochInclusive) && - Objects.equals(this.upperBoundEpochExclusive, enactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.upperBoundEpochExclusive) && - Objects.equals(this.readinessThresholds, enactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf.readinessThresholds); + EnactAtStartOfEpochIfValidatorsReadyConditionAllOf enactAtStartOfEpochIfValidatorsReadyConditionAllOf = (EnactAtStartOfEpochIfValidatorsReadyConditionAllOf) o; + return Objects.equals(this.lowerBoundEpochInclusive, enactAtStartOfEpochIfValidatorsReadyConditionAllOf.lowerBoundEpochInclusive) && + Objects.equals(this.upperBoundEpochExclusive, enactAtStartOfEpochIfValidatorsReadyConditionAllOf.upperBoundEpochExclusive) && + Objects.equals(this.readinessThresholds, enactAtStartOfEpochIfValidatorsReadyConditionAllOf.readinessThresholds); } @Override @@ -161,7 +161,7 @@ public int hashCode() { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("class EnactAtStartOfAnEpochIfSupportedAndWithinBoundsConditionAllOf {\n"); + sb.append("class EnactAtStartOfEpochIfValidatorsReadyConditionAllOf {\n"); sb.append(" lowerBoundEpochInclusive: ").append(toIndentedString(lowerBoundEpochInclusive)).append("\n"); sb.append(" upperBoundEpochExclusive: ").append(toIndentedString(upperBoundEpochExclusive)).append("\n"); sb.append(" readinessThresholds: ").append(toIndentedString(readinessThresholds)).append("\n"); diff --git a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactUnconditionallyAtEpochCondition.java b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochUnconditionallyCondition.java similarity index 67% rename from core/src/main/java/com/radixdlt/api/system/generated/models/EnactUnconditionallyAtEpochCondition.java rename to core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochUnconditionallyCondition.java index 93766dd110..378f89a426 100644 --- a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactUnconditionallyAtEpochCondition.java +++ b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochUnconditionallyCondition.java @@ -24,9 +24,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; -import com.radixdlt.api.system.generated.models.EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition; -import com.radixdlt.api.system.generated.models.EnactUnconditionallyAtEpochCondition; -import com.radixdlt.api.system.generated.models.EnactUnconditionallyAtEpochConditionAllOf; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochIfValidatorsReadyCondition; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochUnconditionallyCondition; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochUnconditionallyConditionAllOf; import com.radixdlt.api.system.generated.models.ProtocolUpdateEnactmentCondition; import com.radixdlt.api.system.generated.models.ProtocolUpdateEnactmentConditionType; import io.swagger.annotations.ApiModel; @@ -36,24 +36,24 @@ import com.radixdlt.api.common.JSON; /** - * EnactUnconditionallyAtEpochCondition + * EnactAtStartOfEpochUnconditionallyCondition */ @JsonPropertyOrder({ - EnactUnconditionallyAtEpochCondition.JSON_PROPERTY_EPOCH + EnactAtStartOfEpochUnconditionallyCondition.JSON_PROPERTY_EPOCH }) @javax.annotation.processing.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class, name = "EnactAtStartOfAnEpochIfSupportedAndWithinBounds"), - @JsonSubTypes.Type(value = EnactUnconditionallyAtEpochCondition.class, name = "EnactUnconditionallyAtEpoch"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochIfValidatorsReadyCondition.class, name = "EnactAtStartOfEpochIfValidatorsReady"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochUnconditionallyCondition.class, name = "EnactAtStartOfEpochUnconditionally"), }) -public class EnactUnconditionallyAtEpochCondition extends ProtocolUpdateEnactmentCondition { +public class EnactAtStartOfEpochUnconditionallyCondition extends ProtocolUpdateEnactmentCondition { public static final String JSON_PROPERTY_EPOCH = "epoch"; private Long epoch; - public EnactUnconditionallyAtEpochCondition epoch(Long epoch) { + public EnactAtStartOfEpochUnconditionallyCondition epoch(Long epoch) { this.epoch = epoch; return this; } @@ -80,7 +80,7 @@ public void setEpoch(Long epoch) { /** - * Return true if this EnactUnconditionallyAtEpochCondition object is equal to o. + * Return true if this EnactAtStartOfEpochUnconditionallyCondition object is equal to o. */ @Override public boolean equals(Object o) { @@ -90,8 +90,8 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - EnactUnconditionallyAtEpochCondition enactUnconditionallyAtEpochCondition = (EnactUnconditionallyAtEpochCondition) o; - return Objects.equals(this.epoch, enactUnconditionallyAtEpochCondition.epoch) && + EnactAtStartOfEpochUnconditionallyCondition enactAtStartOfEpochUnconditionallyCondition = (EnactAtStartOfEpochUnconditionallyCondition) o; + return Objects.equals(this.epoch, enactAtStartOfEpochUnconditionallyCondition.epoch) && super.equals(o); } @@ -103,7 +103,7 @@ public int hashCode() { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("class EnactUnconditionallyAtEpochCondition {\n"); + sb.append("class EnactAtStartOfEpochUnconditionallyCondition {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); sb.append(" epoch: ").append(toIndentedString(epoch)).append("\n"); sb.append("}"); @@ -124,10 +124,10 @@ private String toIndentedString(Object o) { static { // Initialize and register the discriminator mappings. Map> mappings = new HashMap>(); - mappings.put("EnactAtStartOfAnEpochIfSupportedAndWithinBounds", EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class); - mappings.put("EnactUnconditionallyAtEpoch", EnactUnconditionallyAtEpochCondition.class); - mappings.put("EnactUnconditionallyAtEpochCondition", EnactUnconditionallyAtEpochCondition.class); - JSON.registerDiscriminator(EnactUnconditionallyAtEpochCondition.class, "type", mappings); + mappings.put("EnactAtStartOfEpochIfValidatorsReady", EnactAtStartOfEpochIfValidatorsReadyCondition.class); + mappings.put("EnactAtStartOfEpochUnconditionally", EnactAtStartOfEpochUnconditionallyCondition.class); + mappings.put("EnactAtStartOfEpochUnconditionallyCondition", EnactAtStartOfEpochUnconditionallyCondition.class); + JSON.registerDiscriminator(EnactAtStartOfEpochUnconditionallyCondition.class, "type", mappings); } } diff --git a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactUnconditionallyAtEpochConditionAllOf.java b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochUnconditionallyConditionAllOf.java similarity index 81% rename from core/src/main/java/com/radixdlt/api/system/generated/models/EnactUnconditionallyAtEpochConditionAllOf.java rename to core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochUnconditionallyConditionAllOf.java index d99fe19cff..771c713ab9 100644 --- a/core/src/main/java/com/radixdlt/api/system/generated/models/EnactUnconditionallyAtEpochConditionAllOf.java +++ b/core/src/main/java/com/radixdlt/api/system/generated/models/EnactAtStartOfEpochUnconditionallyConditionAllOf.java @@ -28,18 +28,18 @@ /** - * EnactUnconditionallyAtEpochConditionAllOf + * EnactAtStartOfEpochUnconditionallyConditionAllOf */ @JsonPropertyOrder({ - EnactUnconditionallyAtEpochConditionAllOf.JSON_PROPERTY_EPOCH + EnactAtStartOfEpochUnconditionallyConditionAllOf.JSON_PROPERTY_EPOCH }) @javax.annotation.processing.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") -public class EnactUnconditionallyAtEpochConditionAllOf { +public class EnactAtStartOfEpochUnconditionallyConditionAllOf { public static final String JSON_PROPERTY_EPOCH = "epoch"; private Long epoch; - public EnactUnconditionallyAtEpochConditionAllOf epoch(Long epoch) { + public EnactAtStartOfEpochUnconditionallyConditionAllOf epoch(Long epoch) { this.epoch = epoch; return this; } @@ -66,7 +66,7 @@ public void setEpoch(Long epoch) { /** - * Return true if this EnactUnconditionallyAtEpochCondition_allOf object is equal to o. + * Return true if this EnactAtStartOfEpochUnconditionallyCondition_allOf object is equal to o. */ @Override public boolean equals(Object o) { @@ -76,8 +76,8 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - EnactUnconditionallyAtEpochConditionAllOf enactUnconditionallyAtEpochConditionAllOf = (EnactUnconditionallyAtEpochConditionAllOf) o; - return Objects.equals(this.epoch, enactUnconditionallyAtEpochConditionAllOf.epoch); + EnactAtStartOfEpochUnconditionallyConditionAllOf enactAtStartOfEpochUnconditionallyConditionAllOf = (EnactAtStartOfEpochUnconditionallyConditionAllOf) o; + return Objects.equals(this.epoch, enactAtStartOfEpochUnconditionallyConditionAllOf.epoch); } @Override @@ -88,7 +88,7 @@ public int hashCode() { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("class EnactUnconditionallyAtEpochConditionAllOf {\n"); + sb.append("class EnactAtStartOfEpochUnconditionallyConditionAllOf {\n"); sb.append(" epoch: ").append(toIndentedString(epoch)).append("\n"); sb.append("}"); return sb.toString(); diff --git a/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentCondition.java b/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentCondition.java index ae137a86e6..ac360db666 100644 --- a/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentCondition.java +++ b/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentCondition.java @@ -24,8 +24,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonValue; -import com.radixdlt.api.system.generated.models.EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition; -import com.radixdlt.api.system.generated.models.EnactUnconditionallyAtEpochCondition; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochIfValidatorsReadyCondition; +import com.radixdlt.api.system.generated.models.EnactAtStartOfEpochUnconditionallyCondition; import com.radixdlt.api.system.generated.models.ProtocolUpdateEnactmentConditionType; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -42,10 +42,10 @@ @javax.annotation.processing.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class, name = "EnactAtStartOfAnEpochIfSupportedAndWithinBounds"), - @JsonSubTypes.Type(value = EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class, name = "EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition"), - @JsonSubTypes.Type(value = EnactUnconditionallyAtEpochCondition.class, name = "EnactUnconditionallyAtEpoch"), - @JsonSubTypes.Type(value = EnactUnconditionallyAtEpochCondition.class, name = "EnactUnconditionallyAtEpochCondition"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochIfValidatorsReadyCondition.class, name = "EnactAtStartOfEpochIfValidatorsReady"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochIfValidatorsReadyCondition.class, name = "EnactAtStartOfEpochIfValidatorsReadyCondition"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochUnconditionallyCondition.class, name = "EnactAtStartOfEpochUnconditionally"), + @JsonSubTypes.Type(value = EnactAtStartOfEpochUnconditionallyCondition.class, name = "EnactAtStartOfEpochUnconditionallyCondition"), }) public class ProtocolUpdateEnactmentCondition { @@ -122,10 +122,10 @@ private String toIndentedString(Object o) { static { // Initialize and register the discriminator mappings. Map> mappings = new HashMap>(); - mappings.put("EnactAtStartOfAnEpochIfSupportedAndWithinBounds", EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class); - mappings.put("EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition", EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition.class); - mappings.put("EnactUnconditionallyAtEpoch", EnactUnconditionallyAtEpochCondition.class); - mappings.put("EnactUnconditionallyAtEpochCondition", EnactUnconditionallyAtEpochCondition.class); + mappings.put("EnactAtStartOfEpochIfValidatorsReady", EnactAtStartOfEpochIfValidatorsReadyCondition.class); + mappings.put("EnactAtStartOfEpochIfValidatorsReadyCondition", EnactAtStartOfEpochIfValidatorsReadyCondition.class); + mappings.put("EnactAtStartOfEpochUnconditionally", EnactAtStartOfEpochUnconditionallyCondition.class); + mappings.put("EnactAtStartOfEpochUnconditionallyCondition", EnactAtStartOfEpochUnconditionallyCondition.class); mappings.put("ProtocolUpdateEnactmentCondition", ProtocolUpdateEnactmentCondition.class); JSON.registerDiscriminator(ProtocolUpdateEnactmentCondition.class, "type", mappings); } diff --git a/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentConditionType.java b/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentConditionType.java index b876e42030..994ed96f69 100644 --- a/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentConditionType.java +++ b/core/src/main/java/com/radixdlt/api/system/generated/models/ProtocolUpdateEnactmentConditionType.java @@ -28,9 +28,9 @@ */ public enum ProtocolUpdateEnactmentConditionType { - ENACTATSTARTOFANEPOCHIFSUPPORTEDANDWITHINBOUNDS("EnactAtStartOfAnEpochIfSupportedAndWithinBounds"), + ENACTATSTARTOFEPOCHIFVALIDATORSREADY("EnactAtStartOfEpochIfValidatorsReady"), - ENACTUNCONDITIONALLYATEPOCH("EnactUnconditionallyAtEpoch"); + ENACTATSTARTOFEPOCHUNCONDITIONALLY("EnactAtStartOfEpochUnconditionally"); private String value; diff --git a/core/src/main/java/com/radixdlt/api/system/routes/HealthHandler.java b/core/src/main/java/com/radixdlt/api/system/routes/HealthHandler.java index 5431fe5c5e..4e2eff4813 100644 --- a/core/src/main/java/com/radixdlt/api/system/routes/HealthHandler.java +++ b/core/src/main/java/com/radixdlt/api/system/routes/HealthHandler.java @@ -155,16 +155,16 @@ private com.radixdlt.api.system.generated.models.PendingProtocolUpdate pendingPr final var res = new PendingProtocolUpdate() - .protocolVersion(pendingProtocolUpdate.protocolUpdate().nextProtocolVersion()) + .protocolVersion(pendingProtocolUpdate.protocolUpdateTrigger().nextProtocolVersion()) .state(state) .readinessSignalStatus( PendingProtocolUpdate.ReadinessSignalStatusEnum .NO_ACTION_NEEDED /* TODO(protocol-update): implement me */); - if (pendingProtocolUpdate.protocolUpdate().enactmentCondition() - instanceof - ProtocolUpdateEnactmentCondition.EnactAtStartOfAnEpochIfSupportedAndWithinBounds) { - final var readinessSignalName = pendingProtocolUpdate.protocolUpdate().readinessSignalName(); + if (pendingProtocolUpdate.protocolUpdateTrigger().enactmentCondition() + instanceof ProtocolUpdateEnactmentCondition.EnactAtStartOfEpochIfValidatorsReady) { + final var readinessSignalName = + pendingProtocolUpdate.protocolUpdateTrigger().readinessSignalName(); res.setReadinessSignalName(readinessSignalName); } diff --git a/core/src/main/java/com/radixdlt/api/system/system-api-schema.yaml b/core/src/main/java/com/radixdlt/api/system/system-api-schema.yaml index d648324e0f..ba76e9fb49 100644 --- a/core/src/main/java/com/radixdlt/api/system/system-api-schema.yaml +++ b/core/src/main/java/com/radixdlt/api/system/system-api-schema.yaml @@ -469,8 +469,8 @@ components: ProtocolUpdateEnactmentConditionType: type: string enum: - - EnactAtStartOfAnEpochIfSupportedAndWithinBounds - - EnactUnconditionallyAtEpoch + - EnactAtStartOfEpochIfValidatorsReady + - EnactAtStartOfEpochUnconditionally ProtocolUpdateEnactmentCondition: type: object required: @@ -482,9 +482,9 @@ components: propertyName: type mapping: # NOTE: These need to match ProtocolUpdateEnactmentConditionType - EnactAtStartOfAnEpochIfSupportedAndWithinBounds: '#/components/schemas/EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition' - EnactUnconditionallyAtEpoch: '#/components/schemas/EnactUnconditionallyAtEpochCondition' - EnactAtStartOfAnEpochIfSupportedAndWithinBoundsCondition: + EnactAtStartOfEpochIfValidatorsReady: '#/components/schemas/EnactAtStartOfEpochIfValidatorsReadyCondition' + EnactAtStartOfEpochUnconditionally: '#/components/schemas/EnactAtStartOfEpochUnconditionallyCondition' + EnactAtStartOfEpochIfValidatorsReadyCondition: allOf: - $ref: "#/components/schemas/ProtocolUpdateEnactmentCondition" - type: object @@ -503,7 +503,7 @@ components: type: array items: $ref: "#/components/schemas/SignalledReadinessThreshold" - EnactUnconditionallyAtEpochCondition: + EnactAtStartOfEpochUnconditionallyCondition: allOf: - $ref: "#/components/schemas/ProtocolUpdateEnactmentCondition" - type: object diff --git a/core/src/main/java/com/radixdlt/rev2/REv2StateComputer.java b/core/src/main/java/com/radixdlt/rev2/REv2StateComputer.java index 80c1cf21df..13892a497e 100644 --- a/core/src/main/java/com/radixdlt/rev2/REv2StateComputer.java +++ b/core/src/main/java/com/radixdlt/rev2/REv2StateComputer.java @@ -323,6 +323,11 @@ public LedgerProofBundle commit(LedgerExtension ledgerExtension, VertexStoreStat final var newLatestProof = maybePostProtocolUpdateProof.orElse(proof); + // This presence of the protocol update in the proof is validated in rust - to ensure that if + // any protocol update + // is present, our node agrees it should be committed. + // We then can trust that we should trigger the application of the protocol update here. + // NOTE: In the future, we may be able to move this down into Rust. this.latestProof = new LedgerProofBundle( newLatestProof, diff --git a/core/src/test/java/com/radixdlt/api/core/TransactionStreamTest.java b/core/src/test/java/com/radixdlt/api/core/TransactionStreamTest.java index 4c5f00e32c..6d6ef2fe16 100644 --- a/core/src/test/java/com/radixdlt/api/core/TransactionStreamTest.java +++ b/core/src/test/java/com/radixdlt/api/core/TransactionStreamTest.java @@ -82,8 +82,8 @@ import com.radixdlt.message.MessageContent; import com.radixdlt.message.TransactionMessage; import com.radixdlt.protocol.ProtocolConfig; -import com.radixdlt.protocol.ProtocolUpdate; import com.radixdlt.protocol.ProtocolUpdateEnactmentCondition; +import com.radixdlt.protocol.ProtocolUpdateTrigger; import com.radixdlt.rev2.REv2TransactionsAndProofReader; import com.radixdlt.rev2.TransactionBuilder; import com.radixdlt.utils.Bytes; @@ -408,10 +408,9 @@ public void test_core_api_can_return_vm_boot_substate_in_protocol_update_receipt throws Exception { final var protocolConfig = new ProtocolConfig( - "testing-genesis", ImmutableList.of( - new ProtocolUpdate( - ProtocolUpdate.ANEMONE, + new ProtocolUpdateTrigger( + ProtocolUpdateTrigger.ANEMONE, ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(4L)))); try (var test = buildRunningServerTestWithProtocolConfig(30, protocolConfig)) { test.runUntilState(allAtOrOverEpoch(4L)); diff --git a/core/src/test/java/com/radixdlt/p2p/test/MockP2PNetwork.java b/core/src/test/java/com/radixdlt/p2p/test/MockP2PNetwork.java index 4d8796dd21..5fe8b7829b 100644 --- a/core/src/test/java/com/radixdlt/p2p/test/MockP2PNetwork.java +++ b/core/src/test/java/com/radixdlt/p2p/test/MockP2PNetwork.java @@ -116,7 +116,7 @@ void createChannel(int clientPeerIndex, RadixNodeUri serverPeerUri) { clientPeer.injector.getInstance(P2PConfig.class), Addressing.ofNetwork(Network.INTEGRATIONTESTNET), Network.INTEGRATIONTESTNET, - ProtocolConfig.mainnet().genesisProtocolVersion(), + ProtocolConfig.GENESIS_PROTOCOL_VERSION_NAME, clientPeer.injector.getInstance(Metrics.class), clientPeer.injector.getInstance(Serialization.class), new SecureRandom(), @@ -142,7 +142,7 @@ void createChannel(int clientPeerIndex, RadixNodeUri serverPeerUri) { serverPeer.injector.getInstance(P2PConfig.class), Addressing.ofNetwork(Network.INTEGRATIONTESTNET), Network.INTEGRATIONTESTNET, - ProtocolConfig.mainnet().genesisProtocolVersion(), + ProtocolConfig.GENESIS_PROTOCOL_VERSION_NAME, serverPeer.injector.getInstance(Metrics.class), serverPeer.injector.getInstance(Serialization.class), new SecureRandom(), 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 18fdac88e6..3156cebedb 100644 --- a/core/src/test/java/com/radixdlt/p2p/test/P2PTestNetworkRunner.java +++ b/core/src/test/java/com/radixdlt/p2p/test/P2PTestNetworkRunner.java @@ -237,7 +237,7 @@ protected void configure() { selfNodeIndex)); bind(String.class) .annotatedWith(NewestProtocolVersion.class) - .toInstance(ProtocolConfig.mainnet().genesisProtocolVersion()); + .toInstance(ProtocolConfig.GENESIS_PROTOCOL_VERSION_NAME); bind(RuntimeProperties.class).toInstance(properties); bind(Serialization.class).toInstance(DefaultSerialization.getInstance()); bind(DeterministicProcessor.class); 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 fe6650ba25..47203cf615 100644 --- a/core/src/test/java/com/radixdlt/rev2/protocol/AnemoneProtocolUpdateTest.java +++ b/core/src/test/java/com/radixdlt/rev2/protocol/AnemoneProtocolUpdateTest.java @@ -95,7 +95,7 @@ import com.radixdlt.modules.StateComputerConfig; import com.radixdlt.networks.Network; import com.radixdlt.protocol.ProtocolConfig; -import com.radixdlt.protocol.ProtocolUpdate; +import com.radixdlt.protocol.ProtocolUpdateTrigger; import com.radixdlt.rev2.*; import com.radixdlt.statecomputer.RustStateComputer; import com.radixdlt.transactions.PreparedNotarizedTransaction; @@ -108,15 +108,14 @@ import org.junit.rules.TemporaryFolder; public final class AnemoneProtocolUpdateTest { - private static final String PROTOCOL_VERSION_NAME = ProtocolUpdate.ANEMONE; + private static final String PROTOCOL_VERSION_NAME = ProtocolUpdateTrigger.ANEMONE; private static final long PROTOCOL_UPDATE_EPOCH = 4L; // Enact anemone at fixed epoch 4 private static final ProtocolConfig PROTOCOL_CONFIG = new ProtocolConfig( - "testing-genesis", ImmutableList.of( - new ProtocolUpdate( + new ProtocolUpdateTrigger( PROTOCOL_VERSION_NAME, unconditionallyAtEpoch(PROTOCOL_UPDATE_EPOCH)))); @Rule public TemporaryFolder folder = new TemporaryFolder(); 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 0c6a0d84bb..c98401ef46 100644 --- a/core/src/test/java/com/radixdlt/rev2/protocol/ProtocolUpdateWithEpochBoundsTest.java +++ b/core/src/test/java/com/radixdlt/rev2/protocol/ProtocolUpdateWithEpochBoundsTest.java @@ -112,11 +112,13 @@ public static Collection testParameters() { static List fixedEpochScenarios() { final var numValidators = 1; final var protocolUpdate = - new ProtocolUpdate("v2", ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(5)); - final ImmutableList protocolUpdates = ImmutableList.of(protocolUpdate); + new ProtocolUpdateTrigger( + "test-v2", ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(5)); + final ImmutableList protocolUpdateTriggers = + ImmutableList.of(protocolUpdate); final var scenario1 = - new ScenarioBuilder(numValidators, protocolUpdates) + new ScenarioBuilder(numValidators, protocolUpdateTriggers) .atEpoch(5, expectEnactment(protocolUpdate)) .runUntilEpoch(7); @@ -129,8 +131,8 @@ static List scenariosA() { // Enactment bounds: from epoch 5 (inclusive) to epoch 21 (exclusive) // Readiness threshold: required one full epoch at 70% final var protocolUpdate = - new ProtocolUpdate( - "v2", + new ProtocolUpdateTrigger( + "test-v2", ProtocolUpdateEnactmentCondition.singleReadinessThresholdBetweenEpochs( 5, 21, Decimal.ofNonNegativeFraction(7, 10), 1)); final var protocolUpdates = ImmutableList.of(protocolUpdate); @@ -197,12 +199,14 @@ static List scenariosB() { // - two unconditional (formerly known as "fixed-epoch") protocol updates at epochs 5 and 7 // - followed by a readiness-based protocol update with two thresholds final var unconditionalProtocolUpdateAtEpoch5 = - new ProtocolUpdate("v2", ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(5)); + new ProtocolUpdateTrigger( + "test-v2", ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(5)); final var unconditionalProtocolUpdateAtEpoch7 = - new ProtocolUpdate("v3", ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(7)); + new ProtocolUpdateTrigger( + "test-v3", ProtocolUpdateEnactmentCondition.unconditionallyAtEpoch(7)); final var readinessThresholdsProtocolUpdate = - new ProtocolUpdate( - "v4", + new ProtocolUpdateTrigger( + "test-v4", ProtocolUpdateEnactmentCondition.readinessThresholdsBetweenEpochs( 5, 20, @@ -308,9 +312,7 @@ private DeterministicTest createTest(ProtocolConfig protocolConfig) { @Test public void test_protocol_update_scenario() { - final var protocolConfig = - new ProtocolConfig( - ProtocolConfig.testingDefault().genesisProtocolVersion(), scenario.protocolUpdates); + final var protocolConfig = new ProtocolConfig(scenario.protocolUpdateTriggers); try (var test = createTest(protocolConfig)) { test.startAllNodes(); @@ -333,7 +335,7 @@ public void test_protocol_update_scenario() { case ExpectEnactment expectEnactment -> { expectedEnactment = true; verifyProtocolUpdateAtEpoch( - test, currEpoch, expectEnactment.protocolUpdate.nextProtocolVersion()); + test, currEpoch, expectEnactment.protocolUpdateTrigger.nextProtocolVersion()); } case ExpectReadiness expectReadiness -> { verifyCurrentEpochReadiness(test, expectReadiness.verifyFn); @@ -361,7 +363,7 @@ public void test_protocol_update_scenario() { record TestScenario( int numValidators, - ImmutableList protocolUpdates, + ImmutableList protocolUpdateTriggers, ImmutableMap> eventsByEpoch, long runUntilEpoch) {} @@ -371,14 +373,15 @@ record SignalReadiness(String readinessSignalName, int validatorIdx) implements record ExpectReadiness(Function, Boolean> verifyFn) implements TestEvent {} - record ExpectEnactment(ProtocolUpdate protocolUpdate) implements TestEvent {} + record ExpectEnactment(ProtocolUpdateTrigger protocolUpdateTrigger) implements TestEvent {} static TestEvent expectNoReportedReadiness() { return new ExpectReadiness(Map::isEmpty); } - static TestEvent signalReadiness(ProtocolUpdate protocolUpdate, int validatorIdx) { - return signalReadiness(protocolUpdate.readinessSignalName(), validatorIdx); + static TestEvent signalReadiness( + ProtocolUpdateTrigger protocolUpdateTrigger, int validatorIdx) { + return signalReadiness(protocolUpdateTrigger.readinessSignalName(), validatorIdx); } static TestEvent signalReadiness(String protocolUpdateName, int validatorIdx) { @@ -386,11 +389,13 @@ static TestEvent signalReadiness(String protocolUpdateName, int validatorIdx) { } static TestEvent expectOneProtocolReadiness( - ProtocolUpdate protocolUpdate, Decimal expectedReadiness) { + ProtocolUpdateTrigger protocolUpdateTrigger, Decimal expectedReadiness) { return new ExpectReadiness( readiness -> readiness.size() == 1 - && readiness.get(protocolUpdate.readinessSignalName()).equals(expectedReadiness)); + && readiness + .get(protocolUpdateTrigger.readinessSignalName()) + .equals(expectedReadiness)); } static TestEvent expectReadinessToInclude( @@ -400,24 +405,26 @@ static TestEvent expectReadinessToInclude( } static TestEvent expectReadinessToInclude( - ProtocolUpdate protocolUpdate, Decimal expectedReadiness) { - return expectReadinessToInclude(protocolUpdate.readinessSignalName(), expectedReadiness); + ProtocolUpdateTrigger protocolUpdateTrigger, Decimal expectedReadiness) { + return expectReadinessToInclude( + protocolUpdateTrigger.readinessSignalName(), expectedReadiness); } - static TestEvent expectEnactment(ProtocolUpdate protocolUpdate) { - return new ExpectEnactment(protocolUpdate); + static TestEvent expectEnactment(ProtocolUpdateTrigger protocolUpdateTrigger) { + return new ExpectEnactment(protocolUpdateTrigger); } } static class ScenarioBuilder { int numValidators; - ImmutableList protocolUpdates; + ImmutableList protocolUpdateTriggers; Map> eventsByEpochBuilder = new HashMap<>(); long nextEpochMinValue = 3; // No need to handle pre-genesis epochs - ScenarioBuilder(int numValidators, ImmutableList protocolUpdates) { + ScenarioBuilder( + int numValidators, ImmutableList protocolUpdateTriggers) { this.numValidators = numValidators; - this.protocolUpdates = protocolUpdates; + this.protocolUpdateTriggers = protocolUpdateTriggers; } ScenarioBuilder atEpoch(long epoch, TestEvent event) { @@ -442,7 +449,7 @@ TestScenario runUntilEpoch(long epoch) { } return new TestScenario( numValidators, - protocolUpdates, + protocolUpdateTriggers, eventsByEpochBuilder.entrySet().stream() .collect( ImmutableMap.toImmutableMap( From 69f77ee6f2b459b79802e32fbe77f425576c6850 Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 11:49:58 +0000 Subject: [PATCH 2/8] fix: Fix test --- .../rev2/ProtocolConfigGeneratorTest.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java b/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java index 92338f40d1..357a8f9e56 100644 --- a/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java +++ b/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java @@ -80,14 +80,30 @@ public final class ProtocolConfigGeneratorTest { @Test public void generateProtocolConfig() { // Change this, then run the test to generate the config + // NOTE: + // - See `resolve_update_definition_for_version` in `protocol_definition_resolver.rs` for the + // supported + // protocol versions + // - Any protocol version starting "test-" will add a single transaction to ledger at enactment + // - Any protocol version starting "custom-" can be configured with overrides to commit + // arbitrary flash + // transactions. To do this, add an overrides map of protocol version => SBOR encoded bytes of + // Vec>. Where UpdateTransaction is an enum with one option at present + // (FlashTransactionV1). These SBOR encoded bytes should be created in Rust. + // See e.g. protocol/test.rs - although we should add an easier-to-use generator if we choose + // to + // use this in tests. + // Please ask if you need help with this. final var protocolConfig = new ProtocolConfig( - "babylon-genesis", + // List of triggers ImmutableList.of( new ProtocolUpdateTrigger( - "v2", + "test-v2", ProtocolUpdateEnactmentCondition.singleReadinessThresholdBetweenEpochs( - 5, 20, Decimal.ofNonNegativeFraction(7, 10), 1)))); + 5, 20, Decimal.ofNonNegativeFraction(7, 10), 1))), + // Overrides map + Map.of()); final var protocolConfigBytes = NodeSborCodecs.encode(protocolConfig, NodeSborCodecs.resolveCodec(new TypeToken<>() {})); From f9c77b3e2bca12eb14cb528b77b068693aa63a43 Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 11:50:18 +0000 Subject: [PATCH 3/8] tweak: Dumunet needs readiness signals, like stokenet --- .../by_network/dumunet_protocol_config.rs | 17 +++++++++++++++++ .../protocol/protocol_configs/by_network/mod.rs | 2 ++ .../protocol_config_resolver.rs | 1 + 3 files changed, 20 insertions(+) create mode 100644 core-rust/state-manager/src/protocol/protocol_configs/by_network/dumunet_protocol_config.rs diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/dumunet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/dumunet_protocol_config.rs new file mode 100644 index 0000000000..e1e3aa33cc --- /dev/null +++ b/core-rust/state-manager/src/protocol/protocol_configs/by_network/dumunet_protocol_config.rs @@ -0,0 +1,17 @@ +use radix_engine::prelude::*; + +use crate::protocol::*; +use ProtocolUpdateEnactmentCondition::*; + +pub fn dumunet_protocol_config() -> ProtocolConfig { + ProtocolConfig::new_with_triggers(hashmap! { + ANEMONE_PROTOCOL_VERSION => EnactAtStartOfEpochIfValidatorsReady { + lower_bound_inclusive: Epoch::of(1), + upper_bound_exclusive: Epoch::of(1000000), + readiness_thresholds: vec![SignalledReadinessThreshold { + required_ratio_of_stake_supported: dec!("0.80"), + required_consecutive_completed_epochs_of_support: 10, + }], + } + }) +} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs index 8def1d0306..9ba767b8b6 100644 --- a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs +++ b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs @@ -1,7 +1,9 @@ +mod dumunet_protocol_config; mod mainnet_protocol_config; mod stokenet_protocol_config; mod testnet_protocol_config; +pub use dumunet_protocol_config::*; pub use mainnet_protocol_config::*; pub use stokenet_protocol_config::*; pub use testnet_protocol_config::*; diff --git a/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs b/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs index dc78294ff7..96b6cdf9c0 100644 --- a/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs +++ b/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs @@ -10,6 +10,7 @@ impl ProtocolConfigResolver { match network.logical_name.as_str() { "mainnet" => mainnet_protocol_config(), "stokenet" => stokenet_protocol_config(), + "dumunet" => dumunet_protocol_config(), _ => testnet_protocol_config(), } } From 74109b8e4bb4d658d62718359f28d4f14531274b Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 13:54:23 +0000 Subject: [PATCH 4/8] markups: Various tweaks for #816 --- .../rev2/ProtocolConfigGeneratorTest.java | 17 +- .../handlers/status_network_status.rs | 2 +- .../state-manager/src/jni/protocol_update.rs | 2 +- .../state-manager/src/jni/state_computer.rs | 3 +- .../src/protocol/protocol_config.rs | 179 ++++++++++++------ .../src/protocol/protocol_state.rs | 37 ++-- .../definitions/anemone_definition.rs | 4 +- .../definitions/custom_definition.rs | 18 +- .../definitions/default_definition.rs | 2 +- .../definitions/test_definition.rs | 45 ++--- .../protocol_content_overrides.rs | 16 +- .../protocol_definition_resolver.rs | 16 +- .../protocol_update_committer.rs | 14 +- .../protocol_update_definition.rs | 14 +- .../protocol_updates/protocol_updaters.rs | 4 +- core-rust/state-manager/src/protocol/test.rs | 26 ++- core-rust/state-manager/src/staging/result.rs | 4 +- core-rust/state-manager/src/state_computer.rs | 6 +- core-rust/state-manager/src/state_manager.rs | 11 +- .../state-manager/src/store/proofs_gc.rs | 17 +- core-rust/state-manager/src/test/mod.rs | 2 +- .../src/transaction/series_execution.rs | 6 +- core-rust/state-manager/src/types.rs | 7 +- 23 files changed, 252 insertions(+), 200 deletions(-) diff --git a/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java b/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java index 357a8f9e56..36ca05ef28 100644 --- a/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java +++ b/core-rust-bridge/src/test/java/com/radixdlt/rev2/ProtocolConfigGeneratorTest.java @@ -70,6 +70,7 @@ import com.radixdlt.protocol.ProtocolUpdateEnactmentCondition; import com.radixdlt.protocol.ProtocolUpdateTrigger; import com.radixdlt.sbor.NodeSborCodecs; +import java.util.Map; import org.bouncycastle.util.encoders.Hex; import org.junit.Ignore; import org.junit.Test; @@ -82,18 +83,14 @@ public void generateProtocolConfig() { // Change this, then run the test to generate the config // NOTE: // - See `resolve_update_definition_for_version` in `protocol_definition_resolver.rs` for the - // supported - // protocol versions + // supported protocol versions // - Any protocol version starting "test-" will add a single transaction to ledger at enactment // - Any protocol version starting "custom-" can be configured with overrides to commit - // arbitrary flash - // transactions. To do this, add an overrides map of protocol version => SBOR encoded bytes of - // Vec>. Where UpdateTransaction is an enum with one option at present - // (FlashTransactionV1). These SBOR encoded bytes should be created in Rust. - // See e.g. protocol/test.rs - although we should add an easier-to-use generator if we choose - // to - // use this in tests. - // Please ask if you need help with this. + // arbitrary flash transactions. To do this, add an overrides map of protocol version => SBOR + // encoded bytes of Vec>. Where UpdateTransaction is an enum with one + // option at present (FlashTransactionV1). These SBOR encoded bytes should be created in Rust. + // See e.g. protocol/test.rs - although we should add an easier-to-use generator if we choose + // to use this in tests. Please ask if you need help with this. final var protocolConfig = new ProtocolConfig( // List of triggers diff --git a/core-rust/core-api-server/src/core_api/handlers/status_network_status.rs b/core-rust/core-api-server/src/core_api/handlers/status_network_status.rs index cc9a9b5c72..8a36af653a 100644 --- a/core-rust/core-api-server/src/core_api/handlers/status_network_status.rs +++ b/core-rust/core-api-server/src/core_api/handlers/status_network_status.rs @@ -78,7 +78,7 @@ pub(crate) async fn handle_status_network_status( )?)) }) .transpose()?, - current_protocol_version, + current_protocol_version: current_protocol_version.to_string(), })) } diff --git a/core-rust/state-manager/src/jni/protocol_update.rs b/core-rust/state-manager/src/jni/protocol_update.rs index 92988be1bb..3e6b5ffa5a 100644 --- a/core-rust/state-manager/src/jni/protocol_update.rs +++ b/core-rust/state-manager/src/jni/protocol_update.rs @@ -86,7 +86,7 @@ extern "system" fn Java_com_radixdlt_protocol_RustProtocolUpdate_applyProtocolUp jni_sbor_coded_fallible_call( &env, request_payload, - |protocol_version_name: String| -> JavaResult { + |protocol_version_name: ProtocolVersionName| -> JavaResult { let result = JNINodeRustEnvironment::get(&env, j_node_rust_env) .state_manager .apply_protocol_update(&protocol_version_name); diff --git a/core-rust/state-manager/src/jni/state_computer.rs b/core-rust/state-manager/src/jni/state_computer.rs index 36356bef45..a365b7bf69 100644 --- a/core-rust/state-manager/src/jni/state_computer.rs +++ b/core-rust/state-manager/src/jni/state_computer.rs @@ -62,6 +62,7 @@ * permissions under this License. */ +use crate::protocol::ProtocolVersionName; use crate::{protocol::ProtocolState, CommitSummary, LedgerProof}; use jni::objects::{JClass, JObject}; use jni::sys::jbyteArray; @@ -191,7 +192,7 @@ extern "system" fn Java_com_radixdlt_statecomputer_RustStateComputer_newestProto j_node_rust_env: JObject, request_payload: jbyteArray, ) -> jbyteArray { - jni_sbor_coded_call(&env, request_payload, |_: ()| -> String { + jni_sbor_coded_call(&env, request_payload, |_: ()| -> ProtocolVersionName { let env = JNINodeRustEnvironment::get(&env, j_node_rust_env); env.state_manager.newest_protocol_version() }) diff --git a/core-rust/state-manager/src/protocol/protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_config.rs index de809c74b6..04ee4cb51a 100644 --- a/core-rust/state-manager/src/protocol/protocol_config.rs +++ b/core-rust/state-manager/src/protocol/protocol_config.rs @@ -3,12 +3,14 @@ use radix_engine_common::math::Decimal; use radix_engine_common::prelude::{hash, scrypto_encode}; use radix_engine_common::types::Epoch; +use sbor::Sbor; use crate::protocol::*; -use utils::btreeset; +use utils::prelude::*; // This file contains types for node's local static protocol configuration +const MIN_PROTOCOL_VERSION_NAME_LEN: usize = 2; const MAX_PROTOCOL_VERSION_NAME_LEN: usize = 16; /// The `ProtocolConfig` is a static configuration provided per-network, or overriden for testing. @@ -20,7 +22,7 @@ const MAX_PROTOCOL_VERSION_NAME_LEN: usize = 16; /// work out what it should do for the update. #[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] pub struct ProtocolConfig { - pub genesis_protocol_version: String, + pub genesis_protocol_version: ProtocolVersionName, pub protocol_update_triggers: Vec, /// This allows overriding the configuration of a protocol update. /// @@ -36,23 +38,19 @@ pub struct ProtocolConfig { } impl ProtocolConfig { - pub fn new_with_no_updates() -> ProtocolConfig { - Self { - genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), - protocol_update_triggers: vec![], - protocol_update_content_overrides: RawProtocolUpdateContentOverrides::default(), - } + pub fn new_with_no_updates() -> Self { + Self::new_with_triggers::<&str>([]) } - pub fn new_with_triggers<'a>( - triggers: impl IntoIterator, - ) -> ProtocolConfig { + pub fn new_with_triggers>( + triggers: impl IntoIterator, + ) -> Self { Self { - genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), + genesis_protocol_version: ProtocolVersionName::of(GENESIS_PROTOCOL_VERSION).unwrap(), protocol_update_triggers: triggers .into_iter() .map(|(version, enactment_condition)| { - ProtocolUpdateTrigger::of(version, enactment_condition) + ProtocolUpdateTrigger::of(version.into(), enactment_condition) }) .collect(), protocol_update_content_overrides: RawProtocolUpdateContentOverrides::default(), @@ -63,21 +61,22 @@ impl ProtocolConfig { &self, protocol_definition_resolver: &ProtocolDefinitionResolver, ) -> Result<(), String> { - let mut protocol_versions = btreeset!(); + let mut protocol_versions = hashset!(); Self::validate_protocol_version_name( - self.genesis_protocol_version.as_str(), + &self.genesis_protocol_version, protocol_definition_resolver, )?; for protocol_update in self.protocol_update_triggers.iter() { - let protocol_version_name = protocol_update.next_protocol_version.as_str(); + let protocol_version_name = &protocol_update.next_protocol_version; + Self::validate_protocol_version_name( protocol_version_name, protocol_definition_resolver, )?; - if !protocol_versions.insert(protocol_version_name) { + if !protocol_versions.insert(&protocol_update.next_protocol_version) { return Err(format!( "Duplicate specification of protocol version {protocol_version_name}" )); @@ -113,26 +112,24 @@ impl ProtocolConfig { } } - // Note - The protocol_update_content_overrides are validated in the ProtocolDefinitionResolver::new_with_raw_overrides + // Note - The protocol_update_content_overrides contents are validated in the ProtocolDefinitionResolver::new_with_raw_overrides + // But let's check the length here too, which isn't checked there. + for (protocol_version_name, _) in self.protocol_update_content_overrides.iter() { + Self::validate_protocol_version_name( + protocol_version_name, + protocol_definition_resolver, + )?; + } Ok(()) } fn validate_protocol_version_name( - name: &str, + name: &ProtocolVersionName, protocol_definition_resolver: &ProtocolDefinitionResolver, ) -> Result<(), String> { - if name.len() > MAX_PROTOCOL_VERSION_NAME_LEN { - return Err(format!( - "Protocol version ({name}) is longer than {MAX_PROTOCOL_VERSION_NAME_LEN} chars" - )); - } - - if !name.is_ascii() { - return Err(format!( - "Protocol version ({name}) can't use non-ascii characters" - )); - } + name.validate() + .map_err(|err| format!("Protocol version ({name}) is invalid: {err:?}"))?; if !protocol_definition_resolver.recognizes(name) { return Err(format!( @@ -144,19 +141,108 @@ impl ProtocolConfig { } } +// Note - at present we don't validate this on SBOR decode, but we do validate it when +// it's first used for +#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Sbor)] +#[sbor(transparent)] +pub struct ProtocolVersionName(String); + +#[derive(Clone, Debug, Eq, PartialEq, Sbor)] +pub enum ProtocolVersionNameValidationError { + LengthInvalid { + invalid_name: String, + min_inclusive: usize, + max_inclusive: usize, + actual: usize, + }, + CharsInvalid { + invalid_name: String, + allowed_chars: String, + }, +} + +impl ProtocolVersionName { + pub fn of(name: impl Into) -> Result { + let name = Self(name.into()); + name.validate()?; + Ok(name) + } + + /// Usable by persisted names. We panic if not valid in padded_len_16_version_name_for_readiness_signal. + pub fn of_unchecked(name: impl Into) -> Self { + Self(name.into()) + } + + pub fn validate(&self) -> Result<(), ProtocolVersionNameValidationError> { + let length = self.0.len(); + if !(MIN_PROTOCOL_VERSION_NAME_LEN..=MAX_PROTOCOL_VERSION_NAME_LEN).contains(&length) { + return Err(ProtocolVersionNameValidationError::LengthInvalid { + invalid_name: self.0.clone(), + min_inclusive: MIN_PROTOCOL_VERSION_NAME_LEN, + max_inclusive: MAX_PROTOCOL_VERSION_NAME_LEN, + actual: length, + }); + } + let passes_char_check = self.0.chars().all(|c| match c { + _ if c.is_ascii_alphanumeric() => true, + '_' | '-' => true, + _ => false, + }); + if !passes_char_check { + return Err(ProtocolVersionNameValidationError::CharsInvalid { + invalid_name: self.0.clone(), + allowed_chars: "[A-Za-z0-9] and -".to_string(), + }); + } + Ok(()) + } + + pub fn as_ascii_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + pub fn as_str(&self) -> &str { + &self.0 + } + + /// The caller is assumed to have validated the version name before this is called. + pub fn padded_len_16_version_name_for_readiness_signal(&self) -> String { + self.validate() + .expect("Must be valid before extracting readiness signal name"); + std::iter::repeat('0') + .take(16 - self.0.len()) + .chain(self.0.chars()) + .collect() + } +} + +impl From for String { + fn from(value: ProtocolVersionName) -> Self { + value.0 + } +} + +impl fmt::Display for ProtocolVersionName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +/// The `next_protocol_version` must be valid #[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] pub struct ProtocolUpdateTrigger { - pub next_protocol_version: String, + pub next_protocol_version: ProtocolVersionName, pub enactment_condition: ProtocolUpdateEnactmentCondition, } impl ProtocolUpdateTrigger { + /// Note: panics if next_protocol_version is invalid pub fn of( next_protocol_version: impl Into, enactment_condition: ProtocolUpdateEnactmentCondition, ) -> Self { Self { - next_protocol_version: next_protocol_version.into(), + next_protocol_version: ProtocolVersionName::of(next_protocol_version.into()).unwrap(), enactment_condition, } } @@ -167,35 +253,18 @@ impl ProtocolUpdateTrigger { // - next_protocol_version: 16 bytes, // left padded with ASCII 0's if protocol version name is shorter than 16 characters let mut bytes_to_hash = scrypto_encode(&self.enactment_condition).unwrap(); - bytes_to_hash.extend_from_slice(self.next_protocol_version.as_bytes()); + bytes_to_hash.extend_from_slice(self.next_protocol_version.as_ascii_bytes()); let protocol_update_hash = hash(&bytes_to_hash); let mut res = hex::encode(protocol_update_hash)[0..16].to_string(); - res.push_str(&ascii_protocol_version_name_len_16( - &self.next_protocol_version, - )); + res.push_str( + &self + .next_protocol_version + .padded_len_16_version_name_for_readiness_signal(), + ); res } } -/// Returns an ASCII protocol version name truncated/left padded to canonical length (16 bytes) -pub fn ascii_protocol_version_name_len_16(protocol_version_name: &str) -> String { - let filtered_version_name: String = protocol_version_name - .chars() - .filter_map(|c| match c { - _ if c.is_ascii_alphanumeric() => Some(c), - '_' | '-' => Some(c), - ' ' => Some('_'), - _ => None, - }) - .take(16) - .collect(); - - std::iter::repeat('0') - .take(16 - filtered_version_name.len()) - .chain(filtered_version_name.chars()) - .collect() -} - #[derive(Clone, Debug, Eq, PartialEq, ScryptoSbor)] pub enum ProtocolUpdateEnactmentCondition { /// The enactment only proceeds if it's the start of epoch X, diff --git a/core-rust/state-manager/src/protocol/protocol_state.rs b/core-rust/state-manager/src/protocol/protocol_state.rs index 1a270f3199..60be37c6f6 100644 --- a/core-rust/state-manager/src/protocol/protocol_state.rs +++ b/core-rust/state-manager/src/protocol/protocol_state.rs @@ -24,8 +24,8 @@ use ProtocolUpdateEnactmentCondition::*; #[derive(Clone, Debug, Eq, PartialEq, ScryptoCategorize, ScryptoEncode, ScryptoDecode)] pub struct ProtocolState { - pub current_protocol_version: String, - pub enacted_protocol_updates: BTreeMap, + pub current_protocol_version: ProtocolVersionName, + pub enacted_protocol_updates: BTreeMap, pub pending_protocol_updates: Vec, } @@ -67,16 +67,16 @@ fn compute_initial_protocol_update_status< S: QueryableProofStore + IterableProofStore + QueryableTransactionStore, >( store: &S, - protocol_change: &ProtocolUpdateTrigger, + protocol_update_trigger: &ProtocolUpdateTrigger, ) -> InitialProtocolUpdateStatus { - match &protocol_change.enactment_condition { + match &protocol_update_trigger.enactment_condition { EnactAtStartOfEpochIfValidatorsReady { lower_bound_inclusive, upper_bound_exclusive, readiness_thresholds, } => compute_initial_signalled_readiness_protocol_update_status( store, - protocol_change, + protocol_update_trigger, lower_bound_inclusive, upper_bound_exclusive, readiness_thresholds, @@ -91,7 +91,7 @@ fn compute_initial_signalled_readiness_protocol_update_status< S: QueryableProofStore + IterableProofStore + QueryableTransactionStore, >( store: &S, - protocol_update: &ProtocolUpdateTrigger, + protocol_update_trigger: &ProtocolUpdateTrigger, lower_bound_inclusive: &Epoch, upper_bound_exclusive: &Epoch, thresholds: &[SignalledReadinessThreshold], @@ -133,7 +133,7 @@ fn compute_initial_signalled_readiness_protocol_update_status< for (state_version, epoch_change_event) in epoch_change_event_iter { // Update the thresholds update_thresholds_state_at_epoch_change( - protocol_update, + protocol_update_trigger, &epoch_change_event, &mut thresholds_state, ); @@ -210,7 +210,7 @@ impl ProtocolState { }) .collect(); - let expected_already_enacted_protocol_updates: BTreeMap = + let expected_already_enacted_protocol_updates: BTreeMap = initial_statuses .iter() .flat_map(|(protocol_update, status)| match status { @@ -225,15 +225,17 @@ impl ProtocolState { }) .collect(); - let actually_enacted_protocol_updates: BTreeMap = store + let actually_enacted_protocol_updates: BTreeMap = store .get_protocol_update_init_proof_iter(StateVersion::pre_genesis()) .map(|proof| { ( proof.ledger_header.state_version, - proof - .ledger_header - .next_protocol_version - .expect("next_protocol_version is missing in protocol update proof"), + ProtocolVersionName::of_unchecked( + proof + .ledger_header + .next_protocol_version + .expect("next_protocol_version is missing in protocol update proof"), + ), ) }) .collect(); @@ -279,7 +281,7 @@ impl ProtocolState { self: &ProtocolState, local_receipt: &LocalTransactionReceipt, post_execute_state_version: StateVersion, - ) -> (ProtocolState, Option) { + ) -> (ProtocolState, Option) { let Some(post_execute_epoch) = local_receipt .local_execution .next_epoch @@ -390,10 +392,9 @@ impl ProtocolState { new_protocol_state.pending_protocol_updates = pending_protocol_updates; if let Some(next_protocol_version) = next_protocol_version.as_ref() { - new_protocol_state.enacted_protocol_updates.insert( - post_execute_state_version, - next_protocol_version.to_string(), - ); + new_protocol_state + .enacted_protocol_updates + .insert(post_execute_state_version, next_protocol_version.clone()); } (new_protocol_state, next_protocol_version) 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 afeec4f625..53f8bb6192 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 @@ -13,12 +13,12 @@ impl ProtocolUpdateDefinition for AnemoneProtocolUpdateDefinition { type Overrides = (); fn create_updater( - new_protocol_version: &str, + new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, _config: Option, ) -> Box { Box::new(BatchedUpdater::new( - new_protocol_version.to_string(), + new_protocol_version.clone(), Self::state_computer_config(network_definition), AnemoneBatchGenerator, )) 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 d62e09c90b..ab195bb1e0 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 @@ -8,12 +8,14 @@ pub struct CustomProtocolUpdateDefinition; impl CustomProtocolUpdateDefinition { pub const RESERVED_NAME_PREFIX: &'static str = "custom-"; - pub fn subnamed(subname: &str) -> String { - format!("{}{}", Self::RESERVED_NAME_PREFIX, subname) + pub fn subnamed(subname: &str) -> ProtocolVersionName { + ProtocolVersionName::of(format!("{}{}", Self::RESERVED_NAME_PREFIX, subname)).unwrap() } - pub fn matches(protocol_name: &str) -> bool { - protocol_name.starts_with(Self::RESERVED_NAME_PREFIX) + pub fn matches(protocol_name: &ProtocolVersionName) -> bool { + protocol_name + .as_str() + .starts_with(Self::RESERVED_NAME_PREFIX) } } @@ -21,12 +23,12 @@ impl ProtocolUpdateDefinition for CustomProtocolUpdateDefinition { type Overrides = Vec>; fn create_updater( - new_protocol_version: &str, + new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, overrides: Option, ) -> Box { Box::new(BatchedUpdater::new( - new_protocol_version.to_string(), + new_protocol_version.clone(), Self::state_computer_config(network_definition), ArbitraryBatchGenerator { batches: overrides.unwrap_or_default(), @@ -41,8 +43,8 @@ impl ProtocolUpdateDefinition for CustomProtocolUpdateDefinition { } } -struct ArbitraryBatchGenerator { - batches: Vec>, +pub struct ArbitraryBatchGenerator { + pub batches: Vec>, } impl UpdateBatchGenerator for ArbitraryBatchGenerator { 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 676938b189..ee4a3d0a00 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 @@ -7,7 +7,7 @@ impl ProtocolUpdateDefinition for DefaultConfigOnlyProtocolDefinition { type Overrides = (); fn create_updater( - _new_protocol_version: &str, + _new_protocol_version: &ProtocolVersionName, _network_definition: &NetworkDefinition, _overrides: Option, ) -> Box { 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 e8c8698ed7..ef884a919b 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,6 +1,5 @@ use crate::{protocol::*, transaction::FlashTransactionV1}; use radix_engine::{track::StateUpdates, types::*}; -use radix_engine_store_interface::interface::SubstateDatabase; /// Any protocol update beginning `test-` just injects a single transaction. pub struct TestProtocolUpdateDefinition; @@ -8,12 +7,14 @@ pub struct TestProtocolUpdateDefinition; impl TestProtocolUpdateDefinition { pub const RESERVED_NAME_PREFIX: &'static str = "test-"; - pub fn subnamed(subname: &str) -> String { - format!("{}{}", Self::RESERVED_NAME_PREFIX, subname) + pub fn subnamed(subname: &str) -> ProtocolVersionName { + ProtocolVersionName::of(format!("{}{}", Self::RESERVED_NAME_PREFIX, subname)).unwrap() } - pub fn matches(protocol_name: &str) -> bool { - protocol_name.starts_with(Self::RESERVED_NAME_PREFIX) + pub fn matches(protocol_name: &ProtocolVersionName) -> bool { + protocol_name + .as_str() + .starts_with(Self::RESERVED_NAME_PREFIX) } } @@ -21,15 +22,19 @@ impl ProtocolUpdateDefinition for TestProtocolUpdateDefinition { type Overrides = (); fn create_updater( - new_protocol_version: &str, + new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, _overrides: Option, ) -> Box { Box::new(BatchedUpdater::new( - new_protocol_version.to_string(), + new_protocol_version.clone(), Self::state_computer_config(network_definition), - TestBatchGenerator { - protocol_version_name: new_protocol_version.to_string(), + ArbitraryBatchGenerator { + batches: vec![vec![FlashTransactionV1 { + name: format!("{}-txn", &new_protocol_version), + state_updates: StateUpdates::default(), + } + .into()]], }, )) } @@ -40,25 +45,3 @@ impl ProtocolUpdateDefinition for TestProtocolUpdateDefinition { ProtocolStateComputerConfig::default(network_definition.clone()) } } - -struct TestBatchGenerator { - protocol_version_name: String, -} - -impl UpdateBatchGenerator for TestBatchGenerator { - fn generate_batch( - &self, - _store: &impl SubstateDatabase, - batch_index: u32, - ) -> Option> { - match batch_index { - 0 => Some(vec![UpdateTransaction::FlashTransactionV1( - FlashTransactionV1 { - name: format!("{}-txn", &self.protocol_version_name), - state_updates: StateUpdates::default(), - }, - )]), - _ => None, - } - } -} diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs index 48ee47f5f6..baa400ab5a 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_content_overrides.rs @@ -12,7 +12,7 @@ type Overrides = ::Overrides; #[derive(Default, ScryptoSbor)] pub struct ProtocolUpdateContentOverrides { anemone: Option>, - custom: HashMap>, + custom: HashMap>, } impl ProtocolUpdateContentOverrides { @@ -27,16 +27,16 @@ impl ProtocolUpdateContentOverrides { pub fn with_custom( mut self, - custom_name: &str, + custom_name: ProtocolVersionName, config: Overrides, ) -> Self { - if !CustomProtocolUpdateDefinition::matches(custom_name) { + if !CustomProtocolUpdateDefinition::matches(&custom_name) { panic!( "Not an allowed custom protocol update name: {}", custom_name ); } - self.custom.insert(custom_name.to_string(), config); + self.custom.insert(custom_name, config); self } } @@ -47,7 +47,7 @@ impl From for RawProtocolUpdateContentOverrides if let Some(config) = value.anemone { map.insert( - ANEMONE_PROTOCOL_VERSION.to_string(), + ProtocolVersionName::of(ANEMONE_PROTOCOL_VERSION).unwrap(), scrypto_encode(&config).unwrap(), ); } @@ -64,18 +64,18 @@ impl From for RawProtocolUpdateContentOverrides #[derive(Default, Clone, Debug, Eq, PartialEq, Sbor)] #[sbor(transparent)] -pub struct RawProtocolUpdateContentOverrides(HashMap>); +pub struct RawProtocolUpdateContentOverrides(HashMap>); impl RawProtocolUpdateContentOverrides { pub fn none() -> Self { Default::default() } - pub fn iter(&self) -> hash_map::Iter> { + pub fn iter(&self) -> hash_map::Iter> { self.0.iter() } - pub fn get(&self, protocol_version_name: &str) -> Option<&[u8]> { + pub fn get(&self, protocol_version_name: &ProtocolVersionName) -> Option<&[u8]> { self.0.get(protocol_version_name).map(|x| x.as_ref()) } } diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs index 705869e657..629d06f6e2 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs @@ -14,9 +14,9 @@ pub struct ProtocolDefinitionResolver { } fn resolve_update_definition_for_version( - protocol_version_name: &str, + protocol_version_name: &ProtocolVersionName, ) -> Option> { - match protocol_version_name { + match protocol_version_name.as_str() { // Genesis execution is done manually. // Genesis only needs to be supported here to identify which configuration to use. GENESIS_PROTOCOL_VERSION => Some(Box::new(DefaultConfigOnlyProtocolDefinition)), @@ -46,16 +46,16 @@ impl ProtocolDefinitionResolver { pub fn new_with_raw_overrides( network: &NetworkDefinition, - update_config: RawProtocolUpdateContentOverrides, + update_content_overrides: RawProtocolUpdateContentOverrides, ) -> Result { // Validate - for (configured_version, raw_config) in update_config.iter() { + for (configured_version, raw_overrides) in update_content_overrides.iter() { let updater_factory = resolve_update_definition_for_version(configured_version).ok_or( ConfigValidationError::UnknownProtocolVersion(configured_version.to_string()), )?; updater_factory - .validate_raw_overrides(raw_config) + .validate_raw_overrides(raw_overrides) .map_err(|err| { ConfigValidationError::InvalidConfigForProtocolVersion( configured_version.to_string(), @@ -67,17 +67,17 @@ impl ProtocolDefinitionResolver { // Return Ok(ProtocolDefinitionResolver { network: network.clone(), - raw_update_config: update_config, + raw_update_config: update_content_overrides, }) } - pub fn recognizes(&self, protocol_version_name: &str) -> bool { + pub fn recognizes(&self, protocol_version_name: &ProtocolVersionName) -> bool { resolve_update_definition_for_version(protocol_version_name).is_some() } pub fn resolve( &self, - protocol_version_name: &str, + protocol_version_name: &ProtocolVersionName, ) -> Option<(ProtocolStateComputerConfig, Box)> { let definition = resolve_update_definition_for_version(protocol_version_name)?; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs index dc7a71ac0e..24c9772ecc 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_update_committer.rs @@ -30,10 +30,10 @@ impl From for UpdateTransaction { enum ProtocolUpdateProgress { UpdateInitiatedButNothingCommitted { - protocol_version_name: String, + protocol_version_name: ProtocolVersionName, }, UpdateInProgress { - protocol_version_name: String, + protocol_version_name: ProtocolVersionName, last_batch_idx: u32, }, /// This means that the last proof contains no notion of a protocol update, @@ -47,7 +47,7 @@ enum ProtocolUpdateProgress { /// It handles the logic to fulfill the resumability contract of "execute_remaining_state_updates" /// by storing the index of a previously committed transaction batch in the ledger proof. pub struct ProtocolUpdateTransactionCommitter { - protocol_version_name: String, + protocol_version_name: ProtocolVersionName, store: Arc>, execution_configurator: RwLock, ledger_transaction_validator: LedgerTransactionValidator, @@ -55,7 +55,7 @@ pub struct ProtocolUpdateTransactionCommitter { impl ProtocolUpdateTransactionCommitter { pub fn new( - protocol_version_name: String, + protocol_version_name: ProtocolVersionName, store: Arc>, execution_configurator: ExecutionConfigurator, ledger_transaction_validator: LedgerTransactionValidator, @@ -81,7 +81,9 @@ impl ProtocolUpdateTransactionCommitter { latest_proof.ledger_header.next_protocol_version { ProtocolUpdateProgress::UpdateInitiatedButNothingCommitted { - protocol_version_name: latest_proof_protocol_version, + protocol_version_name: ProtocolVersionName::of_unchecked( + latest_proof_protocol_version, + ), } } else { ProtocolUpdateProgress::NotUpdating @@ -91,7 +93,7 @@ impl ProtocolUpdateTransactionCommitter { protocol_version_name, batch_idx, } => ProtocolUpdateProgress::UpdateInProgress { - protocol_version_name: protocol_version_name.to_string(), + protocol_version_name: protocol_version_name.clone(), last_batch_idx: *batch_idx, }, } 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 301dfb9161..84271866a1 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 @@ -24,7 +24,7 @@ pub trait ProtocolUpdateDefinition { -> ProtocolStateComputerConfig; fn create_updater( - new_protocol_version: &str, + new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, overrides: Option, ) -> Box; @@ -39,12 +39,12 @@ pub trait ConfigurableProtocolUpdateDefinition { /// Must return `Ok` if the `raw_config` is None or passed validate. fn create_updater_with_raw_overrides( &self, - new_protocol_version: &str, + new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, - raw_config: Option<&[u8]>, + raw_overrides: Option<&[u8]>, ) -> Result, DecodeError>; - fn validate_raw_overrides(&self, raw_config: &[u8]) -> Result<(), DecodeError>; + fn validate_raw_overrides(&self, raw_overrides: &[u8]) -> Result<(), DecodeError>; } impl ConfigurableProtocolUpdateDefinition for T { @@ -58,7 +58,7 @@ impl ConfigurableProtocolUpdateDefinition for T { /// If no raw config is provided, the default config is used fn create_updater_with_raw_overrides( &self, - new_protocol_version: &str, + new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, raw_overrides: Option<&[u8]>, ) -> Result, DecodeError> { @@ -73,8 +73,8 @@ impl ConfigurableProtocolUpdateDefinition for T { )) } - fn validate_raw_overrides(&self, raw_config: &[u8]) -> Result<(), DecodeError> { - scrypto_decode::<::Overrides>(raw_config).map(|_| ()) + fn validate_raw_overrides(&self, raw_overrides: &[u8]) -> Result<(), DecodeError> { + scrypto_decode::<::Overrides>(raw_overrides).map(|_| ()) } } diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs index 28bd20e769..cc097e3c98 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/protocol_updaters.rs @@ -22,14 +22,14 @@ impl ProtocolUpdater for NoOpProtocolUpdater { } pub(crate) struct BatchedUpdater { - new_protocol_version: String, + new_protocol_version: ProtocolVersionName, new_state_computer_config: ProtocolStateComputerConfig, resolver: R, } impl BatchedUpdater { pub fn new( - new_protocol_version: String, + new_protocol_version: ProtocolVersionName, new_state_computer_config: ProtocolStateComputerConfig, batch_generator: G, ) -> Self { diff --git a/core-rust/state-manager/src/protocol/test.rs b/core-rust/state-manager/src/protocol/test.rs index 92422d8c31..8a15c27d88 100644 --- a/core-rust/state-manager/src/protocol/test.rs +++ b/core-rust/state-manager/src/protocol/test.rs @@ -63,6 +63,7 @@ */ use prometheus::Registry; +use utils::prelude::*; use crate::traits::QueryableProofStore; use radix_engine::blueprints::consensus_manager::{ @@ -92,24 +93,19 @@ const CUSTOM_V2_PROTOCOL_VERSION: &str = "custom-v2"; #[test] fn flash_protocol_update_test() { + let custom_v2_protocol_version = ProtocolVersionName::of(CUSTOM_V2_PROTOCOL_VERSION).unwrap(); + let mut state_manager_config = StateManagerConfig::new_for_testing(tempfile::tempdir().unwrap().path().to_str().unwrap()); // We're enacting an update after another transaction commit let protocol_update_epoch = Epoch::of(3); - state_manager_config.protocol_config = ProtocolConfig { - genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), - protocol_update_triggers: vec![ProtocolUpdateTrigger { - next_protocol_version: CUSTOM_V2_PROTOCOL_VERSION.to_string(), - enactment_condition: - ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally( - protocol_update_epoch, - ), - }], - // This is temporary - we will generate the custom state updates below - protocol_update_content_overrides: RawProtocolUpdateContentOverrides::none(), - }; + state_manager_config.protocol_config = ProtocolConfig::new_with_triggers(hashmap! { + CUSTOM_V2_PROTOCOL_VERSION => ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally( + protocol_update_epoch, + ) + }); // This is a bit of a hack to be able to use fixed flash protocol update let consensus_manager_state_updates = { @@ -129,7 +125,7 @@ fn flash_protocol_update_test() { .protocol_config .protocol_update_content_overrides = ProtocolUpdateContentOverrides::empty() .with_custom( - CUSTOM_V2_PROTOCOL_VERSION, + custom_v2_protocol_version.clone(), vec![vec![FlashTransactionV1 { name: format!("{CUSTOM_V2_PROTOCOL_VERSION}-flash"), state_updates: consensus_manager_state_updates, @@ -152,14 +148,14 @@ fn flash_protocol_update_test() { assert_eq!( prepare_result.next_protocol_version, - Some(CUSTOM_V2_PROTOCOL_VERSION.to_string()) + Some(custom_v2_protocol_version.clone()) ); let pre_protocol_update_state_version = state_manager.database.read_current().max_state_version(); // Now let's apply the protocol update (this would normally be called by Java) - state_manager.apply_protocol_update(CUSTOM_V2_PROTOCOL_VERSION); + state_manager.apply_protocol_update(&custom_v2_protocol_version); let read_db = state_manager.database.read_current(); diff --git a/core-rust/state-manager/src/staging/result.rs b/core-rust/state-manager/src/staging/result.rs index e5fb2f3a23..8dcd1d13c1 100644 --- a/core-rust/state-manager/src/staging/result.rs +++ b/core-rust/state-manager/src/staging/result.rs @@ -65,7 +65,7 @@ use super::ReadableStateTreeStore; use crate::accumulator_tree::storage::{ReadableAccuTreeStore, TreeSlice, WriteableAccuTreeStore}; -use crate::protocol::ProtocolState; +use crate::protocol::{ProtocolState, ProtocolVersionName}; use crate::staging::epoch_handling::EpochAwareAccuTreeFactory; use crate::transaction::LedgerTransactionHash; use crate::{ @@ -117,7 +117,7 @@ pub struct ProcessedCommitResult { pub database_updates: DatabaseUpdates, pub new_substate_node_ancestry_records: Vec, pub new_protocol_state: ProtocolState, - pub next_protocol_version: Option, + pub next_protocol_version: Option, } pub struct HashUpdateContext<'s, S> { diff --git a/core-rust/state-manager/src/state_computer.rs b/core-rust/state-manager/src/state_computer.rs index 18d6220758..1ee8d10677 100644 --- a/core-rust/state-manager/src/state_computer.rs +++ b/core-rust/state-manager/src/state_computer.rs @@ -1262,12 +1262,12 @@ where pub fn handle_protocol_update( &self, - protocol_version_name: &str, + protocol_version_name: &ProtocolVersionName, new_ledger_transaction_validator: LedgerTransactionValidator, ) { *self.ledger_transaction_validator.write() = new_ledger_transaction_validator; - self.protocol_state.write().current_protocol_version = protocol_version_name.to_string(); + self.protocol_state.write().current_protocol_version = protocol_version_name.clone(); let current_header = self .store @@ -1392,7 +1392,7 @@ where *transaction_tree_diff.slice.root() } - pub fn current_protocol_version(&self) -> String { + pub fn current_protocol_version(&self) -> ProtocolVersionName { self.protocol_state.read().current_protocol_version.clone() } diff --git a/core-rust/state-manager/src/state_manager.rs b/core-rust/state-manager/src/state_manager.rs index 7ecb6f7d38..c16f9087fc 100644 --- a/core-rust/state-manager/src/state_manager.rs +++ b/core-rust/state-manager/src/state_manager.rs @@ -76,7 +76,9 @@ use prometheus::Registry; use radix_engine_common::prelude::*; use crate::jni::LedgerSyncLimitsConfig; -use crate::protocol::{ProtocolConfig, ProtocolDefinitionResolver, ProtocolState}; +use crate::protocol::{ + ProtocolConfig, ProtocolDefinitionResolver, ProtocolState, ProtocolVersionName, +}; use crate::store::jmt_gc::StateHashTreeGcConfig; use crate::store::proofs_gc::{LedgerProofsGc, LedgerProofsGcConfig}; use crate::store::traits::proofs::QueryableProofStore; @@ -335,7 +337,10 @@ impl StateManager { } } - pub fn apply_protocol_update(&self, protocol_version_name: &str) -> ProtocolUpdateResult { + pub fn apply_protocol_update( + &self, + protocol_version_name: &ProtocolVersionName, + ) -> ProtocolUpdateResult { let (new_state_computer_config, protocol_updater) = self .protocol_definition_resolver .resolve(protocol_version_name) @@ -378,7 +383,7 @@ impl StateManager { } } - pub fn newest_protocol_version(&self) -> String { + pub fn newest_protocol_version(&self) -> ProtocolVersionName { let protocol_config = &self.config.protocol_config; protocol_config .protocol_update_triggers diff --git a/core-rust/state-manager/src/store/proofs_gc.rs b/core-rust/state-manager/src/store/proofs_gc.rs index 0d0228f5ad..21367881f2 100644 --- a/core-rust/state-manager/src/store/proofs_gc.rs +++ b/core-rust/state-manager/src/store/proofs_gc.rs @@ -340,17 +340,12 @@ mod tests { most_recent_full_resolution_epoch_count: 0, }; // An unconditional protocol update at epoch 5 - config.protocol_config = ProtocolConfig { - genesis_protocol_version: GENESIS_PROTOCOL_VERSION.to_string(), - protocol_update_triggers: vec![ProtocolUpdateTrigger { - next_protocol_version: TestProtocolUpdateDefinition::subnamed("v2"), - enactment_condition: - ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally(Epoch::of( - 5, - )), - }], - protocol_update_content_overrides: ProtocolUpdateContentOverrides::empty().into(), - }; + config.protocol_config = ProtocolConfig::new_with_triggers(hashmap! { + TestProtocolUpdateDefinition::subnamed("v2") => + ProtocolUpdateEnactmentCondition::EnactAtStartOfEpochUnconditionally(Epoch::of( + 5, + )) + }); let state_manager = StateManager::new( config, None, diff --git a/core-rust/state-manager/src/test/mod.rs b/core-rust/state-manager/src/test/mod.rs index 4ab2a0d2ac..eca3faf2da 100644 --- a/core-rust/state-manager/src/test/mod.rs +++ b/core-rust/state-manager/src/test/mod.rs @@ -13,7 +13,7 @@ pub fn commit_round_updates_until_epoch(state_manager: &StateManager, epoch: Epo loop { let (prepare_result, _) = prepare_and_commit_round_update(state_manager); if let Some(next_protocol_version) = prepare_result.next_protocol_version { - state_manager.apply_protocol_update(next_protocol_version.as_str()); + state_manager.apply_protocol_update(&next_protocol_version); } if let Some(next_epoch) = prepare_result.next_epoch { if next_epoch.epoch == epoch { diff --git a/core-rust/state-manager/src/transaction/series_execution.rs b/core-rust/state-manager/src/transaction/series_execution.rs index fa2732b625..517e8ed8f4 100644 --- a/core-rust/state-manager/src/transaction/series_execution.rs +++ b/core-rust/state-manager/src/transaction/series_execution.rs @@ -217,7 +217,7 @@ where self.state_tracker.protocol_state.clone() } - pub fn next_protocol_version(&self) -> Option { + pub fn next_protocol_version(&self) -> Option { self.state_tracker.next_protocol_version() } } @@ -245,7 +245,7 @@ struct StateTracker { ledger_hashes: LedgerHashes, next_epoch: Option, protocol_state: ProtocolState, - next_protocol_version: Option, + next_protocol_version: Option, } impl StateTracker { @@ -301,7 +301,7 @@ impl StateTracker { self.next_protocol_version = result.next_protocol_version.clone(); } - pub fn next_protocol_version(&self) -> Option { + pub fn next_protocol_version(&self) -> Option { self.next_protocol_version.clone() } } diff --git a/core-rust/state-manager/src/types.rs b/core-rust/state-manager/src/types.rs index 25811e783b..f2e274b9e1 100644 --- a/core-rust/state-manager/src/types.rs +++ b/core-rust/state-manager/src/types.rs @@ -63,6 +63,7 @@ */ use crate::accumulator_tree::IsMerklizableHash; +use crate::protocol::ProtocolVersionName; use crate::transaction::*; use crate::{LedgerTransactionOutcome, PartitionChange, SubstateChange}; use radix_engine::types::*; @@ -361,7 +362,7 @@ pub struct PrepareResult { /// Note: this is only used for testing pub rejected: Vec, pub next_epoch: Option, - pub next_protocol_version: Option, + pub next_protocol_version: Option, pub ledger_hashes: LedgerHashes, } @@ -441,7 +442,7 @@ pub enum LedgerProofOrigin { timestamped_signatures: Vec, }, ProtocolUpdate { - protocol_version_name: String, + protocol_version_name: ProtocolVersionName, batch_idx: u32, }, } @@ -486,7 +487,7 @@ pub struct LedgerHeader { pub consensus_parent_round_timestamp_ms: i64, pub proposer_timestamp_ms: i64, pub next_epoch: Option, - pub next_protocol_version: Option, + pub next_protocol_version: Option, } impl From for LedgerHeader { From a2dcd7073ab0a9879bc64a8e0f62d975072a350b Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 14:56:28 +0000 Subject: [PATCH 5/8] markups: Further tweaks to procotol definition resolution --- .../java/com/radixdlt/networks/Network.java | 2 +- core-rust/Cargo.toml | 1 + .../state-manager/src/jni/protocol_update.rs | 2 +- .../src/protocol/protocol_config.rs | 95 +++++++++++----- .../protocol_configs/by_network/mod.rs | 9 -- .../dumunet_protocol_config.rs | 0 .../mainnet_protocol_config.rs | 0 .../src/protocol/protocol_configs/mod.rs | 19 +++- .../protocol_config_resolver.rs | 17 --- .../stokenet_protocol_config.rs | 0 .../testnet_protocol_config.rs | 0 .../src/protocol/protocol_updates/mod.rs | 2 - .../protocol_definition_resolver.rs | 103 ------------------ core-rust/state-manager/src/state_manager.rs | 44 +++----- 14 files changed, 99 insertions(+), 195 deletions(-) delete mode 100644 core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs rename core-rust/state-manager/src/protocol/protocol_configs/{by_network => }/dumunet_protocol_config.rs (100%) rename core-rust/state-manager/src/protocol/protocol_configs/{by_network => }/mainnet_protocol_config.rs (100%) delete mode 100644 core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs rename core-rust/state-manager/src/protocol/protocol_configs/{by_network => }/stokenet_protocol_config.rs (100%) rename core-rust/state-manager/src/protocol/protocol_configs/{by_network => }/testnet_protocol_config.rs (100%) delete mode 100644 core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs diff --git a/common/src/main/java/com/radixdlt/networks/Network.java b/common/src/main/java/com/radixdlt/networks/Network.java index 3f17fe8cb1..d3eddc2c73 100644 --- a/common/src/main/java/com/radixdlt/networks/Network.java +++ b/common/src/main/java/com/radixdlt/networks/Network.java @@ -73,7 +73,7 @@ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public enum Network { - // NOTE: For the protocol configs, see `/protocol_updates/by_network/` in `core-rust` + // NOTE: For protocol configs, see e.g. `[..]/protocol_configs/mainnet_protocol_config.rs` // These are resolved by environment from RadixNodeModule.java. /// Public Facing Permanent Networks (0x00 - 0x09) diff --git a/core-rust/Cargo.toml b/core-rust/Cargo.toml index 10568f92df..69cdcd20b9 100644 --- a/core-rust/Cargo.toml +++ b/core-rust/Cargo.toml @@ -5,6 +5,7 @@ members = [ "core-api-server", "state-manager", ] +resolver = "2" [workspace.dependencies] # DEPENDENCIES ON RADIXDLT-SCRYPTO diff --git a/core-rust/state-manager/src/jni/protocol_update.rs b/core-rust/state-manager/src/jni/protocol_update.rs index 3e6b5ffa5a..05742df131 100644 --- a/core-rust/state-manager/src/jni/protocol_update.rs +++ b/core-rust/state-manager/src/jni/protocol_update.rs @@ -117,7 +117,7 @@ extern "system" fn Java_com_radixdlt_protocol_RustProtocolUpdate_nativeResolveFo request_payload: jbyteArray, ) -> jbyteArray { jni_sbor_coded_call(&env, request_payload, |network: NetworkDefinition| { - ProtocolConfigResolver::resolve_config(&network) + resolve_protocol_config(&network) }) } diff --git a/core-rust/state-manager/src/protocol/protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_config.rs index 04ee4cb51a..f9eb55cd61 100644 --- a/core-rust/state-manager/src/protocol/protocol_config.rs +++ b/core-rust/state-manager/src/protocol/protocol_config.rs @@ -1,5 +1,6 @@ use radix_engine::prelude::ScryptoSbor; use radix_engine_common::math::Decimal; +use radix_engine_common::network::NetworkDefinition; use radix_engine_common::prelude::{hash, scrypto_encode}; use radix_engine_common::types::Epoch; @@ -13,6 +14,28 @@ use utils::prelude::*; const MIN_PROTOCOL_VERSION_NAME_LEN: usize = 2; const MAX_PROTOCOL_VERSION_NAME_LEN: usize = 16; +pub const GENESIS_PROTOCOL_VERSION: &str = "babylon-genesis"; +pub const ANEMONE_PROTOCOL_VERSION: &str = "anemone"; + +pub fn resolve_update_definition_for_version( + protocol_version_name: &ProtocolVersionName, +) -> Option> { + match protocol_version_name.as_str() { + // Genesis execution is done manually. + // Genesis only needs to be supported here to identify which configuration to use. + GENESIS_PROTOCOL_VERSION => Some(Box::new(DefaultConfigOnlyProtocolDefinition)), + ANEMONE_PROTOCOL_VERSION => Some(Box::new(AnemoneProtocolUpdateDefinition)), + // Updates starting "custom-" are intended for use with tests, where the thresholds and config are injected on all nodes + _ if CustomProtocolUpdateDefinition::matches(protocol_version_name) => { + Some(Box::new(CustomProtocolUpdateDefinition)) + } + _ if TestProtocolUpdateDefinition::matches(protocol_version_name) => { + Some(Box::new(TestProtocolUpdateDefinition)) + } + _ => None, + } +} + /// The `ProtocolConfig` is a static configuration provided per-network, or overriden for testing. /// /// When a node commits (or creates a proof), it checks `protocol_update_triggers` to see if a protocol update @@ -28,7 +51,7 @@ pub struct ProtocolConfig { /// /// You can create this with `ProtocolUpdateContentOverrides::empty().into()` or `Default::default()`. /// - /// This wraps an optional `Map>` where the `Vec` is the encoded config + /// This essentially wraps an optional `Map>` where the `Vec` is the encoded config /// for the protocol updater matching the given protocol update. /// /// All nodes must agree on the content overrides used. The content overrides form a part of @@ -53,28 +76,19 @@ impl ProtocolConfig { ProtocolUpdateTrigger::of(version.into(), enactment_condition) }) .collect(), - protocol_update_content_overrides: RawProtocolUpdateContentOverrides::default(), + protocol_update_content_overrides: ProtocolUpdateContentOverrides::empty().into(), } } - pub fn validate( - &self, - protocol_definition_resolver: &ProtocolDefinitionResolver, - ) -> Result<(), String> { + pub fn validate(&self) -> Result<(), String> { let mut protocol_versions = hashset!(); - Self::validate_protocol_version_name( - &self.genesis_protocol_version, - protocol_definition_resolver, - )?; + Self::validate_and_resolve_protocol_definition(&self.genesis_protocol_version)?; for protocol_update in self.protocol_update_triggers.iter() { let protocol_version_name = &protocol_update.next_protocol_version; - Self::validate_protocol_version_name( - protocol_version_name, - protocol_definition_resolver, - )?; + Self::validate_and_resolve_protocol_definition(protocol_version_name)?; if !protocol_versions.insert(&protocol_update.next_protocol_version) { return Err(format!( @@ -114,30 +128,53 @@ impl ProtocolConfig { // Note - The protocol_update_content_overrides contents are validated in the ProtocolDefinitionResolver::new_with_raw_overrides // But let's check the length here too, which isn't checked there. - for (protocol_version_name, _) in self.protocol_update_content_overrides.iter() { - Self::validate_protocol_version_name( - protocol_version_name, - protocol_definition_resolver, - )?; + for (protocol_version_name, raw_overrides) in self.protocol_update_content_overrides.iter() + { + let definition = Self::validate_and_resolve_protocol_definition(protocol_version_name)?; + + definition + .validate_raw_overrides(raw_overrides) + .map_err(|err| { + format!( + "Protocol version ({protocol_version_name}) has invalid raw overrides: {err:?}" + ) + })?; } Ok(()) } - fn validate_protocol_version_name( + pub fn resolve_config_and_updater( + &self, + network: &NetworkDefinition, + protocol_version_name: &ProtocolVersionName, + ) -> Option<(ProtocolStateComputerConfig, Box)> { + let definition = resolve_update_definition_for_version(protocol_version_name)?; + + let config = definition.resolve_state_computer_config(network); + + // Unwrap is allowed because we have already validated the raw config + let updater = definition + .create_updater_with_raw_overrides( + protocol_version_name, + network, + self.protocol_update_content_overrides + .get(protocol_version_name), + ) + .unwrap(); + + Some((config, updater)) + } + + fn validate_and_resolve_protocol_definition( name: &ProtocolVersionName, - protocol_definition_resolver: &ProtocolDefinitionResolver, - ) -> Result<(), String> { + ) -> Result, String> { name.validate() .map_err(|err| format!("Protocol version ({name}) is invalid: {err:?}"))?; - if !protocol_definition_resolver.recognizes(name) { - return Err(format!( - "Protocol version ({name}) does not have a recognized definition" - )); - } - - Ok(()) + resolve_update_definition_for_version(name).ok_or_else(|| { + format!("Protocol version ({name}) does not have a recognized definition") + }) } } diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs b/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs deleted file mode 100644 index 9ba767b8b6..0000000000 --- a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod dumunet_protocol_config; -mod mainnet_protocol_config; -mod stokenet_protocol_config; -mod testnet_protocol_config; - -pub use dumunet_protocol_config::*; -pub use mainnet_protocol_config::*; -pub use stokenet_protocol_config::*; -pub use testnet_protocol_config::*; diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/dumunet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/dumunet_protocol_config.rs similarity index 100% rename from core-rust/state-manager/src/protocol/protocol_configs/by_network/dumunet_protocol_config.rs rename to core-rust/state-manager/src/protocol/protocol_configs/dumunet_protocol_config.rs diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/mainnet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/mainnet_protocol_config.rs similarity index 100% rename from core-rust/state-manager/src/protocol/protocol_configs/by_network/mainnet_protocol_config.rs rename to core-rust/state-manager/src/protocol/protocol_configs/mainnet_protocol_config.rs diff --git a/core-rust/state-manager/src/protocol/protocol_configs/mod.rs b/core-rust/state-manager/src/protocol/protocol_configs/mod.rs index 4ab6cca19f..4ab0b2623d 100644 --- a/core-rust/state-manager/src/protocol/protocol_configs/mod.rs +++ b/core-rust/state-manager/src/protocol/protocol_configs/mod.rs @@ -1,5 +1,16 @@ -mod by_network; -mod protocol_config_resolver; +mod dumunet_protocol_config; +mod mainnet_protocol_config; +mod stokenet_protocol_config; +mod testnet_protocol_config; -pub use by_network::*; -pub use protocol_config_resolver::*; +use crate::protocol::*; +use radix_engine_common::network::NetworkDefinition; + +pub fn resolve_protocol_config(network: &NetworkDefinition) -> ProtocolConfig { + match network.logical_name.as_str() { + "mainnet" => mainnet_protocol_config::mainnet_protocol_config(), + "stokenet" => stokenet_protocol_config::stokenet_protocol_config(), + "dumunet" => dumunet_protocol_config::dumunet_protocol_config(), + _ => testnet_protocol_config::testnet_protocol_config(), + } +} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs b/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs deleted file mode 100644 index 96b6cdf9c0..0000000000 --- a/core-rust/state-manager/src/protocol/protocol_configs/protocol_config_resolver.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::by_network::*; -use crate::protocol::*; - -use radix_engine_common::network::NetworkDefinition; - -pub struct ProtocolConfigResolver; - -impl ProtocolConfigResolver { - pub fn resolve_config(network: &NetworkDefinition) -> ProtocolConfig { - match network.logical_name.as_str() { - "mainnet" => mainnet_protocol_config(), - "stokenet" => stokenet_protocol_config(), - "dumunet" => dumunet_protocol_config(), - _ => testnet_protocol_config(), - } - } -} diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/stokenet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/stokenet_protocol_config.rs similarity index 100% rename from core-rust/state-manager/src/protocol/protocol_configs/by_network/stokenet_protocol_config.rs rename to core-rust/state-manager/src/protocol/protocol_configs/stokenet_protocol_config.rs diff --git a/core-rust/state-manager/src/protocol/protocol_configs/by_network/testnet_protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_configs/testnet_protocol_config.rs similarity index 100% rename from core-rust/state-manager/src/protocol/protocol_configs/by_network/testnet_protocol_config.rs rename to core-rust/state-manager/src/protocol/protocol_configs/testnet_protocol_config.rs diff --git a/core-rust/state-manager/src/protocol/protocol_updates/mod.rs b/core-rust/state-manager/src/protocol/protocol_updates/mod.rs index 0fe73f7f19..429d3d4d4e 100644 --- a/core-rust/state-manager/src/protocol/protocol_updates/mod.rs +++ b/core-rust/state-manager/src/protocol/protocol_updates/mod.rs @@ -1,13 +1,11 @@ mod definitions; mod protocol_content_overrides; -mod protocol_definition_resolver; mod protocol_update_committer; mod protocol_update_definition; mod protocol_updaters; pub use definitions::*; pub use protocol_content_overrides::*; -pub use protocol_definition_resolver::*; pub use protocol_update_committer::*; pub use protocol_update_definition::*; pub use protocol_updaters::*; diff --git a/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs b/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs deleted file mode 100644 index 629d06f6e2..0000000000 --- a/core-rust/state-manager/src/protocol/protocol_updates/protocol_definition_resolver.rs +++ /dev/null @@ -1,103 +0,0 @@ -use super::definitions::*; -use crate::protocol::*; -use sbor::DecodeError; - -use radix_engine_common::network::NetworkDefinition; -use utils::prelude::*; - -pub const GENESIS_PROTOCOL_VERSION: &str = "babylon-genesis"; -pub const ANEMONE_PROTOCOL_VERSION: &str = "anemone"; - -pub struct ProtocolDefinitionResolver { - network: NetworkDefinition, - raw_update_config: RawProtocolUpdateContentOverrides, -} - -fn resolve_update_definition_for_version( - protocol_version_name: &ProtocolVersionName, -) -> Option> { - match protocol_version_name.as_str() { - // Genesis execution is done manually. - // Genesis only needs to be supported here to identify which configuration to use. - GENESIS_PROTOCOL_VERSION => Some(Box::new(DefaultConfigOnlyProtocolDefinition)), - ANEMONE_PROTOCOL_VERSION => Some(Box::new(AnemoneProtocolUpdateDefinition)), - // Updates starting "custom-" are intended for use with tests, where the thresholds and config are injected on all nodes - _ if CustomProtocolUpdateDefinition::matches(protocol_version_name) => { - Some(Box::new(CustomProtocolUpdateDefinition)) - } - _ if TestProtocolUpdateDefinition::matches(protocol_version_name) => { - Some(Box::new(TestProtocolUpdateDefinition)) - } - _ => None, - } -} - -impl ProtocolDefinitionResolver { - pub fn new(network: &NetworkDefinition) -> ProtocolDefinitionResolver { - Self::new_with_raw_overrides(network, Default::default()).unwrap() - } - - pub fn new_with_overrides( - network: &NetworkDefinition, - update_config: ProtocolUpdateContentOverrides, - ) -> Result { - Self::new_with_raw_overrides(network, update_config.into()) - } - - pub fn new_with_raw_overrides( - network: &NetworkDefinition, - update_content_overrides: RawProtocolUpdateContentOverrides, - ) -> Result { - // Validate - for (configured_version, raw_overrides) in update_content_overrides.iter() { - let updater_factory = resolve_update_definition_for_version(configured_version).ok_or( - ConfigValidationError::UnknownProtocolVersion(configured_version.to_string()), - )?; - - updater_factory - .validate_raw_overrides(raw_overrides) - .map_err(|err| { - ConfigValidationError::InvalidConfigForProtocolVersion( - configured_version.to_string(), - err, - ) - })?; - } - - // Return - Ok(ProtocolDefinitionResolver { - network: network.clone(), - raw_update_config: update_content_overrides, - }) - } - - pub fn recognizes(&self, protocol_version_name: &ProtocolVersionName) -> bool { - resolve_update_definition_for_version(protocol_version_name).is_some() - } - - pub fn resolve( - &self, - protocol_version_name: &ProtocolVersionName, - ) -> Option<(ProtocolStateComputerConfig, Box)> { - let definition = resolve_update_definition_for_version(protocol_version_name)?; - - let config = definition.resolve_state_computer_config(&self.network); - - // Unwrap is allowed because we have already validated the raw config - let updater = definition - .create_updater_with_raw_overrides( - protocol_version_name, - &self.network, - self.raw_update_config.get(protocol_version_name), - ) - .unwrap(); - - Some((config, updater)) - } -} - -#[derive(Debug)] -pub enum ConfigValidationError { - UnknownProtocolVersion(String), - InvalidConfigForProtocolVersion(String, DecodeError), -} diff --git a/core-rust/state-manager/src/state_manager.rs b/core-rust/state-manager/src/state_manager.rs index c16f9087fc..bf837e94a3 100644 --- a/core-rust/state-manager/src/state_manager.rs +++ b/core-rust/state-manager/src/state_manager.rs @@ -76,9 +76,7 @@ use prometheus::Registry; use radix_engine_common::prelude::*; use crate::jni::LedgerSyncLimitsConfig; -use crate::protocol::{ - ProtocolConfig, ProtocolDefinitionResolver, ProtocolState, ProtocolVersionName, -}; +use crate::protocol::{ProtocolConfig, ProtocolState, ProtocolVersionName}; use crate::store::jmt_gc::StateHashTreeGcConfig; use crate::store::proofs_gc::{LedgerProofsGc, LedgerProofsGcConfig}; use crate::store::traits::proofs::QueryableProofStore; @@ -153,7 +151,6 @@ pub struct StateManager { pub execution_configurator: Arc>, pub committability_validator: Arc>>, pub transaction_previewer: Arc>>, - pub protocol_definition_resolver: Arc, } impl StateManager { @@ -183,19 +180,8 @@ impl StateManager { ); let database = Arc::new(lock_factory.named("database").new_state_lock(raw_db)); - let protocol_definition_resolver = ProtocolDefinitionResolver::new_with_raw_overrides( - &network, - config - .protocol_config - .protocol_update_content_overrides - .clone(), - ) - .unwrap_or_else(|err| panic!("Invalid protocol update content overrides: {:?}", err)); - - if let Err(err) = config - .protocol_config - .validate(&protocol_definition_resolver) - { + + if let Err(err) = config.protocol_config.validate() { panic!("Protocol misconfiguration: {}", err); }; @@ -205,15 +191,15 @@ impl StateManager { ); let initial_protocol_version = &initial_protocol_state.current_protocol_version; - let (initial_state_computer_config, initial_protocol_updater) = - protocol_definition_resolver - .resolve(initial_protocol_version) - .unwrap_or_else(|| { - panic!( - "Initial protocol version on boot ({}) was not known in the resolver", - initial_protocol_version - ) - }); + let (initial_state_computer_config, initial_protocol_updater) = config + .protocol_config + .resolve_config_and_updater(&config.network_definition, initial_protocol_version) + .unwrap_or_else(|| { + panic!( + "Initial protocol version on boot ({}) was not known in the resolver", + initial_protocol_version + ) + }); let execution_configurator = Arc::new( lock_factory @@ -333,7 +319,6 @@ impl StateManager { execution_configurator, committability_validator, transaction_previewer, - protocol_definition_resolver: Arc::new(protocol_definition_resolver), } } @@ -342,8 +327,9 @@ impl StateManager { protocol_version_name: &ProtocolVersionName, ) -> ProtocolUpdateResult { let (new_state_computer_config, protocol_updater) = self - .protocol_definition_resolver - .resolve(protocol_version_name) + .config + .protocol_config + .resolve_config_and_updater(&self.config.network_definition, protocol_version_name) .unwrap_or_else(|| { panic!( "Protocol update to version {} was triggered, but isn't known in the resolver", From 0c728711adc25d8c69faa0c40e78c52eeacd898c Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 15:10:15 +0000 Subject: [PATCH 6/8] markups: Further minor tweaks --- .../src/protocol/protocol_config.rs | 10 +++------- .../protocol_update_definition.rs | 17 +++++++++-------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/core-rust/state-manager/src/protocol/protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_config.rs index f9eb55cd61..4d55911675 100644 --- a/core-rust/state-manager/src/protocol/protocol_config.rs +++ b/core-rust/state-manager/src/protocol/protocol_config.rs @@ -134,11 +134,9 @@ impl ProtocolConfig { definition .validate_raw_overrides(raw_overrides) - .map_err(|err| { - format!( + .map_err(|err| format!( "Protocol version ({protocol_version_name}) has invalid raw overrides: {err:?}" - ) - })?; + ))?; } Ok(()) @@ -153,15 +151,13 @@ impl ProtocolConfig { let config = definition.resolve_state_computer_config(network); - // Unwrap is allowed because we have already validated the raw config let updater = definition .create_updater_with_raw_overrides( protocol_version_name, network, self.protocol_update_content_overrides .get(protocol_version_name), - ) - .unwrap(); + ); Some((config, updater)) } 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 84271866a1..3ded2ffdff 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 @@ -36,13 +36,14 @@ pub trait ConfigurableProtocolUpdateDefinition { network_definition: &NetworkDefinition, ) -> ProtocolStateComputerConfig; - /// Must return `Ok` if the `raw_config` is None or passed validate. + /// This method panics if the `raw_overrides` is present and invalid. + /// A caller should have first validated with validate_raw_overrides. fn create_updater_with_raw_overrides( &self, new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, raw_overrides: Option<&[u8]>, - ) -> Result, DecodeError>; + ) -> Box; fn validate_raw_overrides(&self, raw_overrides: &[u8]) -> Result<(), DecodeError>; } @@ -55,22 +56,22 @@ impl ConfigurableProtocolUpdateDefinition for T { Self::state_computer_config(network_definition) } - /// If no raw config is provided, the default config is used fn create_updater_with_raw_overrides( &self, new_protocol_version: &ProtocolVersionName, network_definition: &NetworkDefinition, raw_overrides: Option<&[u8]>, - ) -> Result, DecodeError> { + ) -> Box { let overrides = raw_overrides - .map(scrypto_decode::<::Overrides>) - .transpose()?; + .map(|overrides| scrypto_decode::<::Overrides>(overrides) + .expect("Raw overrides should have been validated before being passed to this method") + ); - Ok(Self::create_updater( + Self::create_updater( new_protocol_version, network_definition, overrides, - )) + ) } fn validate_raw_overrides(&self, raw_overrides: &[u8]) -> Result<(), DecodeError> { From 20afd23099065b6179d9fbe6c84fcb74c941193a Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 15:13:52 +0000 Subject: [PATCH 7/8] fix: Spotless apply --- .../src/protocol/protocol_config.rs | 19 ++++++++++--------- .../protocol_update_definition.rs | 17 +++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/core-rust/state-manager/src/protocol/protocol_config.rs b/core-rust/state-manager/src/protocol/protocol_config.rs index 4d55911675..faba2d9ed4 100644 --- a/core-rust/state-manager/src/protocol/protocol_config.rs +++ b/core-rust/state-manager/src/protocol/protocol_config.rs @@ -134,9 +134,11 @@ impl ProtocolConfig { definition .validate_raw_overrides(raw_overrides) - .map_err(|err| format!( + .map_err(|err| { + format!( "Protocol version ({protocol_version_name}) has invalid raw overrides: {err:?}" - ))?; + ) + })?; } Ok(()) @@ -151,13 +153,12 @@ impl ProtocolConfig { let config = definition.resolve_state_computer_config(network); - let updater = definition - .create_updater_with_raw_overrides( - protocol_version_name, - network, - self.protocol_update_content_overrides - .get(protocol_version_name), - ); + let updater = definition.create_updater_with_raw_overrides( + protocol_version_name, + network, + self.protocol_update_content_overrides + .get(protocol_version_name), + ); Some((config, updater)) } 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 3ded2ffdff..60af84a717 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 @@ -62,16 +62,13 @@ impl ConfigurableProtocolUpdateDefinition for T { network_definition: &NetworkDefinition, raw_overrides: Option<&[u8]>, ) -> Box { - let overrides = raw_overrides - .map(|overrides| scrypto_decode::<::Overrides>(overrides) - .expect("Raw overrides should have been validated before being passed to this method") - ); - - Self::create_updater( - new_protocol_version, - network_definition, - overrides, - ) + let overrides = raw_overrides.map(|overrides| { + scrypto_decode::<::Overrides>(overrides).expect( + "Raw overrides should have been validated before being passed to this method", + ) + }); + + Self::create_updater(new_protocol_version, network_definition, overrides) } fn validate_raw_overrides(&self, raw_overrides: &[u8]) -> Result<(), DecodeError> { From 74765828f1ae56040bd9a624231240c3758b3344 Mon Sep 17 00:00:00 2001 From: David Edey Date: Tue, 23 Jan 2024 16:40:45 +0000 Subject: [PATCH 8/8] fix: Remove ProtocolConfigV0 --- .../com/radixdlt/protocol/ProtocolConfig.java | 6 +- .../radixdlt/protocol/ProtocolConfigV0.java | 86 ------------------- .../java/com/radixdlt/RadixNodeModule.java | 4 +- 3 files changed, 5 insertions(+), 91 deletions(-) delete mode 100644 core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java index ea15a00863..28aeda8373 100644 --- a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java +++ b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfig.java @@ -96,13 +96,11 @@ public static void registerCodec(CodecMap codecMap) { codecs -> StructCodec.fromRecordComponents(ProtocolConfig.class, codecs)); } - public static ProtocolConfig sborDecodeWithFallbackForOldVersions(byte[] encoded) { + public static ProtocolConfig sborDecode(byte[] encoded, String errorMessage) { try { return NodeSborCodecs.decode(encoded, NodeSborCodecs.resolveCodec(new TypeToken<>() {})); } catch (SborDecodeException ex) { - return NodeSborCodecs.decode( - encoded, NodeSborCodecs.resolveCodec(new TypeToken() {})) - .update(); + throw new RuntimeException(errorMessage, ex); } } diff --git a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java b/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java deleted file mode 100644 index 6adb873723..0000000000 --- a/core-rust-bridge/src/main/java/com/radixdlt/protocol/ProtocolConfigV0.java +++ /dev/null @@ -1,86 +0,0 @@ -/* 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.protocol; - -import com.google.common.collect.ImmutableList; -import com.radixdlt.sbor.codec.CodecMap; -import com.radixdlt.sbor.codec.StructCodec; -import java.util.Map; - -/** - * A legacy format still used in some tests. We attempt to decode this as well as the new format. - */ -public record ProtocolConfigV0( - String genesisProtocolVersion, ImmutableList protocolUpdateTriggers) { - public static void registerCodec(CodecMap codecMap) { - codecMap.register( - ProtocolConfigV0.class, - codecs -> StructCodec.fromRecordComponents(ProtocolConfigV0.class, codecs)); - } - - public ProtocolConfig update() { - return new ProtocolConfig(genesisProtocolVersion, protocolUpdateTriggers, Map.of()); - } -} diff --git a/core/src/main/java/com/radixdlt/RadixNodeModule.java b/core/src/main/java/com/radixdlt/RadixNodeModule.java index 67d6b11772..5191971c32 100644 --- a/core/src/main/java/com/radixdlt/RadixNodeModule.java +++ b/core/src/main/java/com/radixdlt/RadixNodeModule.java @@ -360,7 +360,9 @@ protected void configure() { final ProtocolConfig protocolConfig; if (!customProtocolConfig.isEmpty()) { protocolConfig = - ProtocolConfig.sborDecodeWithFallbackForOldVersions(Hex.decode(customProtocolConfig)); + ProtocolConfig.sborDecode( + Hex.decode(customProtocolConfig), + "Could not decode protocol custom_config. It may need regenerating."); } else { protocolConfig = ProtocolConfig.resolveForNetwork(NetworkDefinition.from(network)); }