diff --git a/CHANGELOG.md b/CHANGELOG.md
index be895d7c..c4183a4b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
## Unreleased changes
+## 6.0.0
+
+- Support for Concordium Node version 8 API changes:
+ - Expand enum `ProtocolVersion` with `P8` variant.
+ - Introduce `IsSuspended` field on `AccountBaker` and `BakerPoolStatus`.
+ - Introduce new baker events `BakerSuspended` and `BakerResumed` for when a validator choose to suspend.
+ - Introduce `ChainParametersV3` with `ValidatorScoreParameters`.
+ - Introduce `Parameter` field for `ContractInitializedEvent`.
+ - Introduce `EffectValidatorScoreParameters` for pending updates to `ValidatorScoreParameters`.
+ - Introduce `ValidatorScoreParametersUpdate` and `UpdateType.ValidatorScoreParametersUpdate` for update payloads.
+ - Introduce `ValidatorPrimedForSuspension` and `ValidatorSuspended` as `ISpecialEvent`.
+
## 5.0.0
- Added
diff --git a/concordium-base b/concordium-base
index 31a168d0..67227da0 160000
--- a/concordium-base
+++ b/concordium-base
@@ -1 +1 @@
-Subproject commit 31a168d0af2c568e8e6dd7931a404601b2cee090
+Subproject commit 67227da0e592f8be107f313d3b6e6bc2ee706bc0
diff --git a/src/Concordium.Sdk.csproj b/src/Concordium.Sdk.csproj
index 3c933262..0ee51040 100644
--- a/src/Concordium.Sdk.csproj
+++ b/src/Concordium.Sdk.csproj
@@ -15,7 +15,7 @@
concordium;concordium-net-sdk;blockchain;sdk;
Concordium
ConcordiumNetSdk
- 5.0.0
+ 6.0.0
icon.png
README.md
MPL-2.0
diff --git a/src/Types/AccountStakingInfo.cs b/src/Types/AccountStakingInfo.cs
index 97d8db72..f72de6c5 100644
--- a/src/Types/AccountStakingInfo.cs
+++ b/src/Types/AccountStakingInfo.cs
@@ -43,7 +43,8 @@ public sealed record AccountBaker(
CcdAmount StakedAmount,
BakerInfo BakerInfo,
AccountBakerPendingChange? PendingChange,
- BakerPoolInfo? BakerPoolInfo
+ BakerPoolInfo? BakerPoolInfo,
+ bool IsSuspended
) : IAccountStakingInfo
{
internal static AccountBaker From(Grpc.V2.AccountStakingInfo.Types.Baker stakeBaker) =>
@@ -52,7 +53,8 @@ internal static AccountBaker From(Grpc.V2.AccountStakingInfo.Types.Baker stakeBa
PendingChange: AccountBakerPendingChange.From(stakeBaker.PendingChange),
RestakeEarnings: stakeBaker.RestakeEarnings,
StakedAmount: CcdAmount.From(stakeBaker.StakedAmount),
- BakerPoolInfo: BakerPoolInfo.From(stakeBaker.PoolInfo)
+ BakerPoolInfo: BakerPoolInfo.From(stakeBaker.PoolInfo),
+ IsSuspended: stakeBaker.IsSuspended
);
///
diff --git a/src/Types/BakerEvent.cs b/src/Types/BakerEvent.cs
index 94649254..338cb8a0 100644
--- a/src/Types/BakerEvent.cs
+++ b/src/Types/BakerEvent.cs
@@ -50,6 +50,8 @@ internal static IBakerEvent From(BakerEvent bakerEvent) =>
AmountFraction.From(bakerEvent.BakerSetFinalizationRewardCommission.FinalizationRewardCommission)
),
BakerEvent.EventOneofCase.DelegationRemoved => new BakerEventDelegationRemoved(DelegatorId.From(bakerEvent.DelegationRemoved.DelegatorId)),
+ BakerEvent.EventOneofCase.BakerSuspended => new BakerEventSuspended(BakerId.From(bakerEvent.BakerSuspended.BakerId)),
+ BakerEvent.EventOneofCase.BakerResumed => new BakerEventResumed(BakerId.From(bakerEvent.BakerResumed.BakerId)),
BakerEvent.EventOneofCase.None =>
throw new MissingEnumException(bakerEvent.EventCase),
_ => throw new MissingEnumException(bakerEvent.EventCase)
@@ -142,3 +144,15 @@ public sealed record BakerSetFinalizationRewardCommissionEvent(BakerId BakerId,
///
/// Delegator's id
public sealed record BakerEventDelegationRemoved(DelegatorId DelegatorId) : IBakerEvent;
+
+///
+/// A baker has been suspended.
+///
+/// Suspended baker's id
+public sealed record BakerEventSuspended(BakerId BakerId) : IBakerEvent;
+
+///
+/// A baker has been resumed.
+///
+/// The resumed baker's id
+public sealed record BakerEventResumed(BakerId BakerId) : IBakerEvent;
diff --git a/src/Types/BakerPoolStatus.cs b/src/Types/BakerPoolStatus.cs
index a9a9c585..53dd729e 100644
--- a/src/Types/BakerPoolStatus.cs
+++ b/src/Types/BakerPoolStatus.cs
@@ -31,6 +31,10 @@ namespace Concordium.Sdk.Types;
///
/// Any pending change to the baker's stake.
/// Total capital staked across all pools.
+///
+/// A flag indicating whether the pool owner is suspended.
+/// Also `False` if the protocol version does not support validator suspension or the pool is removed.
+///
public sealed record BakerPoolStatus(
BakerId BakerId,
AccountAddress BakerAddress,
@@ -40,7 +44,9 @@ public sealed record BakerPoolStatus(
BakerPoolInfo? PoolInfo,
CurrentPaydayBakerPoolStatus? CurrentPaydayStatus,
CcdAmount AllPoolTotalCapital,
- BakerPoolPendingChange? BakerStakePendingChange)
+ BakerPoolPendingChange? BakerStakePendingChange,
+ bool IsSuspended
+)
{
internal static BakerPoolStatus From(Grpc.V2.PoolInfoResponse poolInfoResponse) =>
new(
@@ -52,6 +58,7 @@ internal static BakerPoolStatus From(Grpc.V2.PoolInfoResponse poolInfoResponse)
poolInfoResponse.PoolInfo != null ? BakerPoolInfo.From(poolInfoResponse.PoolInfo) : null,
CurrentPaydayBakerPoolStatus.From(poolInfoResponse.CurrentPaydayInfo),
CcdAmount.From(poolInfoResponse.AllPoolTotalCapital),
- BakerPoolPendingChange.From(poolInfoResponse.EquityPendingChange)
- );
+ BakerPoolPendingChange.From(poolInfoResponse.EquityPendingChange),
+ poolInfoResponse.IsSuspended
+ );
}
diff --git a/src/Types/ChainParameters.cs b/src/Types/ChainParameters.cs
index 58a9d3f2..6b7a351c 100644
--- a/src/Types/ChainParameters.cs
+++ b/src/Types/ChainParameters.cs
@@ -21,6 +21,8 @@ internal static IChainParameters From(ChainParameters chainParameters) =>
ChainParametersV1.From(chainParameters.V1),
ChainParameters.ParametersOneofCase.V2 =>
ChainParametersV2.From(chainParameters.V2),
+ ChainParameters.ParametersOneofCase.V3 =>
+ ChainParametersV3.From(chainParameters.V3),
ChainParameters.ParametersOneofCase.None =>
throw new MissingEnumException(chainParameters.ParametersCase),
_ => throw new MissingEnumException(chainParameters.ParametersCase)
@@ -29,7 +31,74 @@ internal static IChainParameters From(ChainParameters chainParameters) =>
///
/// Values of chain parameters that can be updated via chain updates.
-/// This applies to protocol version 6 and up.
+/// This applies to protocol version 8 and up.
+///
+/// Consensus protocol version 2 timeout parameters.
+/// Minimum time interval between blocks.
+/// Maximum energy allowed per block.
+/// Euro per energy exchange rate.
+/// Micro ccd per euro exchange rate.
+/// Parameters related to cooldowns when staking.
+/// Parameters related mint rate and reward period.
+/// The limit for the number of account creations in a block.
+/// Parameters related to the distribution of newly minted CCD.
+/// Parameters related to the distribution of transaction fees.
+/// Parameters related to the distribution from the GAS account.
+/// Address of the foundation account.
+/// Parameters for baker pools.
+/// The finalization committee parameters.
+/// Validator score parameters.
+/// Root Keys
+/// Level 1 Keys
+/// Level 2 Keys
+public sealed record ChainParametersV3(
+ TimeoutParameters TimeoutParameters,
+ TimeSpan MinBlockTime,
+ EnergyAmount BlockEnergyLimit,
+ ExchangeRate EuroPerEnergy,
+ ExchangeRate MicroCcdPerEuro,
+ CooldownParameters CooldownParameters,
+ TimeParameters TimeParameters,
+ CredentialsPerBlockLimit AccountCreationLimit,
+ MintDistributionCpv1 MintDistribution,
+ TransactionFeeDistribution TransactionFeeDistribution,
+ GasRewardsCpv2 GasRewards,
+ AccountAddress FoundationAccount,
+ PoolParameters PoolParameters,
+ FinalizationCommitteeParameters FinalizationCommitteeParameters,
+ ValidatorScoreParameters ValidatorScoreParameters,
+ HigherLevelKeys RootKeys,
+ HigherLevelKeys Level1Keys,
+ AuthorizationsV1 Level2Keys
+) : IChainParameters
+{
+ internal static ChainParametersV3 From(Grpc.V2.ChainParametersV3 chainParams) =>
+ new(
+ TimeoutParameters.From(chainParams.ConsensusParameters.TimeoutParameters),
+ TimeSpan.FromMilliseconds(chainParams.ConsensusParameters.MinBlockTime.Value),
+ EnergyAmount.From(chainParams.ConsensusParameters.BlockEnergyLimit),
+ ExchangeRate.From(chainParams.EuroPerEnergy),
+ ExchangeRate.From(chainParams.MicroCcdPerEuro),
+ CooldownParameters.From(chainParams.CooldownParameters),
+ TimeParameters.From(chainParams.TimeParameters),
+ CredentialsPerBlockLimit.From(chainParams.AccountCreationLimit),
+ MintDistributionCpv1.From(chainParams.MintDistribution),
+ TransactionFeeDistribution.From(chainParams.TransactionFeeDistribution),
+ GasRewardsCpv2.From(chainParams.GasRewards),
+ AccountAddress.From(chainParams.FoundationAccount),
+ PoolParameters.From(chainParams.PoolParameters),
+ FinalizationCommitteeParameters.From(chainParams.FinalizationCommitteeParameters),
+ ValidatorScoreParameters.From(chainParams.ValidatorScoreParameters),
+ Types.RootKeys.From(chainParams.RootKeys),
+ Types.Level1Keys.From(chainParams.Level1Keys),
+ AuthorizationsV1.From(chainParams.Level2Keys)
+ );
+}
+
+
+///
+/// Values of chain parameters that can be updated via chain updates.
+/// This applies to protocol version 6 and 7.
///
/// Consensus protocol version 2 timeout parameters.
/// Minimum time interval between blocks.
diff --git a/src/Types/ContractInitializedEvent.cs b/src/Types/ContractInitializedEvent.cs
index f40dc62d..87d7108e 100644
--- a/src/Types/ContractInitializedEvent.cs
+++ b/src/Types/ContractInitializedEvent.cs
@@ -11,13 +11,15 @@ namespace Concordium.Sdk.Types;
/// Represent the CCD amount the contract instance was initialized with.
/// The name of the contract.
/// A list of events generated by a smart contract.
+/// The parameter passed to the initializer (introduced by Concordium Node v8 and up).
public sealed record ContractInitializedEvent(
ContractVersion ContractVersion,
ModuleReference ModuleReference,
ContractAddress ContractAddress,
CcdAmount Amount,
ContractName InitName,
- IList Events
+ IList Events,
+ Parameter? Parameter
)
{
///
@@ -36,8 +38,9 @@ internal static ContractInitializedEvent From(Grpc.V2.ContractInitializedEvent i
var events = initializedEvent.Events
.Select(e => new ContractEvent(e.Value.ToByteArray()))
.ToList();
+ var parameter = initializedEvent.Parameter == null ? null : Parameter.From(initializedEvent.Parameter);
return new ContractInitializedEvent(contractVersion, moduleReference, contractAddress, amount,
- initName, events);
+ initName, events, parameter);
}
///
diff --git a/src/Types/PendingUpdate.cs b/src/Types/PendingUpdate.cs
index 8af2a1c3..edc19b67 100644
--- a/src/Types/PendingUpdate.cs
+++ b/src/Types/PendingUpdate.cs
@@ -47,6 +47,8 @@ internal static PendingUpdate From(Grpc.V2.PendingUpdate pendingUpdate) =>
GrpcEffect.MinBlockTime => new EffectMinBlockTime(TimeSpan.FromMilliseconds(pendingUpdate.MinBlockTime.Value)),
GrpcEffect.BlockEnergyLimit => new EffectBlockEnergyLimit(EnergyAmount.From(pendingUpdate.BlockEnergyLimit)),
GrpcEffect.FinalizationCommitteeParameters => new EffectFinalizationCommitteeParameters(FinalizationCommitteeParameters.From(pendingUpdate.FinalizationCommitteeParameters)),
+ GrpcEffect.ValidatorScoreParameters =>
+ new EffectValidatorScoreParameters(ValidatorScoreParameters.From(pendingUpdate.ValidatorScoreParameters)),
GrpcEffect.None => throw new NotImplementedException(),
_ => throw new MissingEnumException(pendingUpdate.EffectCase),
}
@@ -104,3 +106,5 @@ public sealed record EffectMinBlockTime(TimeSpan MinBlockTime) : IEffect;
public sealed record EffectBlockEnergyLimit(EnergyAmount BlockEnergyLimit) : IEffect;
/// Updates to the finalization committee for for chain parameters version 2.
public sealed record EffectFinalizationCommitteeParameters(FinalizationCommitteeParameters FinalizationCommitteeParameters) : IEffect;
+/// Updates to the validator score for chain parameters version 3.
+public sealed record EffectValidatorScoreParameters(ValidatorScoreParameters ValidatorScoreParameters) : IEffect;
diff --git a/src/Types/ProtocolVersion.cs b/src/Types/ProtocolVersion.cs
index ca768737..61320311 100644
--- a/src/Types/ProtocolVersion.cs
+++ b/src/Types/ProtocolVersion.cs
@@ -40,6 +40,13 @@ public enum ProtocolVersion
/// implements tokenomics changes.
///
P7,
+ ///
+ /// Protocol `P8` supports suspending inactive validators automatically
+ /// when they consistently fail to participate in the consensus protocol.
+ /// Suspended validators can be reactivated manually by a transaction
+ /// from the validator's account.
+ ///
+ P8,
}
@@ -66,6 +73,7 @@ internal static ProtocolVersion Into(this Grpc.V2.ProtocolVersion protocolVersio
Grpc.V2.ProtocolVersion._5 => ProtocolVersion.P5,
Grpc.V2.ProtocolVersion._6 => ProtocolVersion.P6,
Grpc.V2.ProtocolVersion._7 => ProtocolVersion.P7,
+ Grpc.V2.ProtocolVersion._8 => ProtocolVersion.P8,
_ => throw new MissingEnumException(protocolVersion)
};
}
diff --git a/src/Types/SpecialEvent.cs b/src/Types/SpecialEvent.cs
index b390a166..d2a66c01 100644
--- a/src/Types/SpecialEvent.cs
+++ b/src/Types/SpecialEvent.cs
@@ -32,6 +32,10 @@ internal static ISpecialEvent From(BlockSpecialEvent specialEvent) =>
BlockAccrueReward.From(specialEvent.BlockAccrueReward),
BlockSpecialEvent.EventOneofCase.PaydayPoolReward =>
PaydayPoolReward.From(specialEvent.PaydayPoolReward),
+ BlockSpecialEvent.EventOneofCase.ValidatorPrimedForSuspension =>
+ ValidatorPrimedForSuspension.From(specialEvent.ValidatorPrimedForSuspension),
+ BlockSpecialEvent.EventOneofCase.ValidatorSuspended =>
+ ValidatorSuspended.From(specialEvent.ValidatorSuspended),
BlockSpecialEvent.EventOneofCase.None => throw new MissingEnumException(specialEvent.EventCase),
_ => throw new MissingEnumException(specialEvent.EventCase)
};
@@ -233,3 +237,37 @@ internal static PaydayPoolReward From(BlockSpecialEvent.Types.PaydayPoolReward p
);
}
+///
+/// A validator that is primed for suspension at the next snapshot epoch due to too
+/// many missed rounds.
+///
+/// The id of the primed validator.
+/// The account of the primed validator.
+public sealed record ValidatorPrimedForSuspension(
+ BakerId BakerId,
+ AccountAddress Account
+) : ISpecialEvent
+{
+ internal static ValidatorPrimedForSuspension From(BlockSpecialEvent.Types.ValidatorPrimedForSuspension primed) =>
+ new(
+ BakerId: BakerId.From(primed.BakerId),
+ Account: AccountAddress.From(primed.Account)
+ );
+}
+
+///
+/// The id of a validator that got suspended due to too many missed rounds.
+///
+/// The id of the suspended validator.
+/// The account of the suspended validator.
+public sealed record ValidatorSuspended(
+ BakerId BakerId,
+ AccountAddress Account
+) : ISpecialEvent
+{
+ internal static ValidatorSuspended From(BlockSpecialEvent.Types.ValidatorSuspended suspended) =>
+ new(
+ BakerId: BakerId.From(suspended.BakerId),
+ Account: AccountAddress.From(suspended.Account)
+ );
+}
diff --git a/src/Types/UpdatePayload.cs b/src/Types/UpdatePayload.cs
index 623ef3d3..9ddee24a 100644
--- a/src/Types/UpdatePayload.cs
+++ b/src/Types/UpdatePayload.cs
@@ -62,6 +62,8 @@ public enum UpdateType
BlockEnergyLimitUpdate,
/// Update of finalization committee parameters.
FinalizationCommitteeParametersUpdate,
+ /// Update of validator score parameters.
+ ValidatorScoreParametersUpdate,
}
///
@@ -99,6 +101,7 @@ public static UpdateType From(IUpdatePayload payload) =>
TimeoutParametersUpdate => UpdateType.TimeoutParametersUpdate,
TimeParametersCpv1Update => UpdateType.TimeParametersCpv1Update,
TransactionFeeDistributionUpdate => UpdateType.TransactionFeeDistributionUpdate,
+ ValidatorScoreParametersUpdate => UpdateType.ValidatorScoreParametersUpdate,
_ => throw new MissingTypeException(payload)
};
@@ -149,6 +152,8 @@ internal static IUpdatePayload From(UpdatePayload payload) =>
BlockEnergyLimitUpdate.From(payload.BlockEnergyLimitUpdate),
UpdatePayload.PayloadOneofCase.FinalizationCommitteeParametersUpdate =>
FinalizationCommitteeParametersUpdate.From(payload.FinalizationCommitteeParametersUpdate),
+ UpdatePayload.PayloadOneofCase.ValidatorScoreParametersUpdate =>
+ ValidatorScoreParametersUpdate.From(payload.ValidatorScoreParametersUpdate),
UpdatePayload.PayloadOneofCase.None =>
throw new MissingEnumException(payload.PayloadCase),
_ => throw new MissingEnumException(payload.PayloadCase)
@@ -370,3 +375,11 @@ public sealed record FinalizationCommitteeParametersUpdate
internal static FinalizationCommitteeParametersUpdate From(Grpc.V2.FinalizationCommitteeParameters parameters) => new(FinalizationCommitteeParameters.From(parameters));
}
+///
+/// Finalization committee parameters (chain parameters version 2).
+///
+public sealed record ValidatorScoreParametersUpdate
+ (ValidatorScoreParameters ValidatorScoreParameters) : IUpdatePayload
+{
+ internal static ValidatorScoreParametersUpdate From(Grpc.V2.ValidatorScoreParameters parameters) => new(ValidatorScoreParameters.From(parameters));
+}
diff --git a/src/Types/ValidatorScoreParameters.cs b/src/Types/ValidatorScoreParameters.cs
new file mode 100644
index 00000000..66af924f
--- /dev/null
+++ b/src/Types/ValidatorScoreParameters.cs
@@ -0,0 +1,13 @@
+namespace Concordium.Sdk.Types;
+
+///
+/// Validator score parameters (introduced in Concordium Protocol 8).
+///
+/// The maximal number of missed rounds before a validator gets suspended.
+public sealed record ValidatorScoreParameters(
+ ulong MaximumMissedRounds
+)
+{
+ internal static ValidatorScoreParameters From(Grpc.V2.ValidatorScoreParameters param) =>
+ new(param.MaximumMissedRounds);
+}
diff --git a/tests/UnitTests/Types/ContractInitializedEventTests.cs b/tests/UnitTests/Types/ContractInitializedEventTests.cs
index 5bf3b6fd..0acb28fb 100644
--- a/tests/UnitTests/Types/ContractInitializedEventTests.cs
+++ b/tests/UnitTests/Types/ContractInitializedEventTests.cs
@@ -27,7 +27,9 @@ public void WhenGetDeserializedEventsFromContractInitializedEvent_ThenReturnPars
new ContractAddress(1, 0),
CcdAmount.Zero,
result.ContractName!,
- new List { new(Convert.FromHexString(eventMessage)) });
+ new List { new(Convert.FromHexString(eventMessage)) },
+ Parameter.Empty()
+ );
// Act
var events = contractInitializedEvent.GetDeserializedEvents(versionedModuleSchema);